git-svn-id: https://google-glog.googlecode.com/svn/trunk@2 eb4d4688-79bd-11dd-afb4-1d65580434c0
This commit is contained in:
2008-10-07 05:43:05 +00:00
parent 1c5d6dc798
commit b8b4db46fe
83 changed files with 55124 additions and 0 deletions

2
AUTHORS Normal file
View File

@ -0,0 +1,2 @@
opensource@google.com

28
COPYING Normal file
View File

@ -0,0 +1,28 @@
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.

6
ChangeLog Normal file
View File

@ -0,0 +1,6 @@
2008-10-07 Google Inc. <opensource@google.com>
* google-glog: initial release:
The glog package contains a library that implements application-level
logging. This library provides logging APIs based on C++-style
streams and various helper macros.

230
INSTALL Normal file
View File

@ -0,0 +1,230 @@
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

172
Makefile.am Normal file
View File

@ -0,0 +1,172 @@
## Process this file with automake to produce Makefile.in
# Make sure that when we re-make ./configure, we get the macros we need
ACLOCAL_AMFLAGS = -I m4
# This is so we can #include <glog/foo>
AM_CPPFLAGS = -I$(top_srcdir)/src
# This is mostly based on configure options
AM_CXXFLAGS =
# These are good warnings to turn on by default
if GCC
AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
endif
# These are x86-specific, having to do with frame-pointers
if X86_64
if ENABLE_FRAME_POINTERS
AM_CXXFLAGS += -fno-omit-frame-pointer
else
# TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS),
# before setting this.
AM_CXXFLAGS += -DNO_FRAME_POINTER
endif
endif
glogincludedir = $(includedir)/glog
## The .h files you want to install (that is, .h files that people
## who install this package can include in their own applications.)
gloginclude_HEADERS = src/glog/log_severity.h src/glog/logging.h src/glog/raw_logging.h src/glog/vlog_is_on.h src/glog/stl_logging.h
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
## This is for HTML and other documentation you want to install.
## Add your documentation files (in doc/) in addition to these
## top-level boilerplate files. Also add a TODO file if you have one.
dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
doc/designstyle.css doc/glog.html
## The libraries (.so's) you want to install
lib_LTLIBRARIES =
## unittests you want to run when people type 'make check'.
## TESTS is for binary unittests, check_SCRIPTS for script-based unittests.
## TESTS_ENVIRONMENT sets environment variables for when you run unittest,
## but it only seems to take effect for *binary* unittests (argh!)
TESTS =
TESTS_ENVIRONMENT =
check_SCRIPTS =
# Every time you add a unittest to check_SCRIPTS, add it here too
noinst_SCRIPTS =
# Binaries used for script-based unittests.
TEST_BINARIES =
TESTS += logging_unittest
logging_unittest_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/logging_unittest.cc
logging_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
logging_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
logging_unittest_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
check_SCRIPTS += logging_striplog_test_sh
noinst_SCRIPTS += src/logging_striplog_test.sh
logging_striplog_test_sh: logging_striptest0 logging_striptest2 logging_striptest10
$(top_srcdir)/src/logging_striplog_test.sh
check_SCRIPTS += demangle_unittest_sh
noinst_SCRIPTS += src/demangle_unittest.sh
demangle_unittest_sh: demangle_unittest
$(top_srcdir)/demangle_unittest # force to create lt-demangle_unittest
$(top_srcdir)/src/demangle_unittest.sh
TEST_BINARIES += logging_striptest0
logging_striptest0_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/logging_striptest_main.cc
logging_striptest0_CXXFLAGS = $(PTHREAD_CFLAGS)
logging_striptest0_LDFLAGS = $(PTHREAD_CFLAGS)
logging_striptest0_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TEST_BINARIES += logging_striptest2
logging_striptest2_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/logging_striptest2.cc
logging_striptest2_CXXFLAGS = $(PTHREAD_CFLAGS)
logging_striptest2_LDFLAGS = $(PTHREAD_CFLAGS)
logging_striptest2_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TEST_BINARIES += logging_striptest10
logging_striptest10_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/logging_striptest10.cc
logging_striptest10_CXXFLAGS = $(PTHREAD_CFLAGS)
logging_striptest10_LDFLAGS = $(PTHREAD_CFLAGS)
logging_striptest10_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TESTS += demangle_unittest
demangle_unittest_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/demangle_unittest.cc
demangle_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
demangle_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
demangle_unittest_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TESTS += stacktrace_unittest
stacktrace_unittest_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/stacktrace_unittest.cc
stacktrace_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
stacktrace_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
stacktrace_unittest_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TESTS += symbolize_unittest
symbolize_unittest_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/symbolize_unittest.cc
symbolize_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
symbolize_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
symbolize_unittest_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TESTS += stacktrace_framesizes_unittest
stacktrace_framesizes_unittest_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/stacktrace_framesizes_unittest.cc
stacktrace_framesizes_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
stacktrace_framesizes_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
stacktrace_framesizes_unittest_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
TESTS += stl_logging_unittest
stl_logging_unittest_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/stl_logging_unittest.cc
stl_logging_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
stl_logging_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
stl_logging_unittest_LDADD = libglog.la $(PTHREAD_LIBS) $(GFLAGS_LIBS)
## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
lib_LTLIBRARIES += libglog.la
libglog_la_SOURCES = $(gloginclude_HEADERS) src/config.h \
src/logging.cc src/raw_logging.cc src/vlog_is_on.cc \
src/utilities.cc src/utilities.h \
src/demangle.cc src/demangle.h \
src/stacktrace.cc src/stacktrace.h \
src/stacktrace_generic-inl.h \
src/stacktrace_libunwind-inl.h \
src/stacktrace_powerpc-inl.h \
src/stacktrace_x86-inl.h \
src/stacktrace_x86_64-inl.h \
src/symbolize.cc src/symbolize.h \
src/base/mutex.h src/base/googleinit.h \
src/base/commandlineflags.h src/googletest.h
libglog_la_CXXFLAGS = $(PTRHEAD_CFLAGS) -DNDEBUG
libglog_la_LDFLAGS = $(PTRHEAD_CFLAGS)
libglog_la_LIBADD = $(PTHREAD_LIBS)
## ^^^^ END OF RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
## This should always include $(TESTS), but may also include other
## binaries that you compile but don't want automatically installed.
noinst_PROGRAMS = $(TESTS) $(TEST_BINARIES)
rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
@cd packages && ./rpm.sh ${PACKAGE} ${VERSION}
deb: dist-gzip packages/deb.sh packages/deb/*
@cd packages && ./deb.sh ${PACKAGE} ${VERSION}
# TODO(hamaji): We don't support Visual Studio for now.
## Windows wants write permission to .vcproj files and maybe even sln files.
#dist-hook:
# test -e "$(distdir)/vsprojects" \
# && chmod -R u+w $(distdir)/*.sln $(distdir)/vsprojects/
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
$(SCRIPTS) src/logging_unittest.err src/demangle_unittest.txt

1185
Makefile.in Normal file

File diff suppressed because it is too large Load Diff

0
NEWS Normal file
View File

5
README Normal file
View File

@ -0,0 +1,5 @@
This repository contains a C++ implementation of the Google logging
module. Documentation for the implementation is in doc/.
See INSTALL for (generic) installation instructions for C++: basically
./configure && make && make install

7274
aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

25
autogen.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/sh
# Before using, you should figure out all the .m4 macros that your
# configure.m4 script needs and make sure they exist in the autoconf/
# directory.
#
# These are the files that this script might edit:
# aclocal.m4 configure Makefile.in src/config.h.in \
# depcomp config.guess config.sub install-sh missing mkinstalldirs \
# ltmain.sh
#
# Here's a command you can run to see what files aclocal will import:
# aclocal -I ../autoconf --output=- | sed -n 's/^m4_include..\([^]]*\).*/\1/p'
set -ex
rm -rf autom4te.cache
aclocal --force -I m4
grep -q LIBTOOL configure.ac && libtoolize -c -f
autoconf -f -W all,no-obsolete
autoheader -f -W all
automake -a -c -f -W all
rm -rf autom4te.cache
exit 0

99
compile Executable file
View File

@ -0,0 +1,99 @@
#! /bin/sh
# Wrapper for compilers which do not understand `-c -o'.
# Copyright 1999, 2000 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Usage:
# compile PROGRAM [ARGS]...
# `-o FOO.o' is removed from the args passed to the actual compile.
prog=$1
shift
ofile=
cfile=
args=
while test $# -gt 0; do
case "$1" in
-o)
# configure might choose to run compile as `compile cc -o foo foo.c'.
# So we do something ugly here.
ofile=$2
shift
case "$ofile" in
*.o | *.obj)
;;
*)
args="$args -o $ofile"
ofile=
;;
esac
;;
*.c)
cfile=$1
args="$args $1"
;;
*)
args="$args $1"
;;
esac
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no `-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# `.c' file was seen then we are probably linking. That is also
# ok.
exec "$prog" $args
fi
# Name of file we expect compiler to create.
cofile=`echo $cfile | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
# Create the lock directory.
# Note: use `[/.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo $cofile | sed -e 's|[/.-]|_|g'`.d
while true; do
if mkdir $lockdir > /dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir $lockdir; exit 1" 1 2 15
# Run the compile.
"$prog" $args
status=$?
if test -f "$cofile"; then
mv "$cofile" "$ofile"
fi
rmdir $lockdir
exit $status

1466
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1579
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

23182
configure vendored Executable file

File diff suppressed because it is too large Load Diff

120
configure.ac Normal file
View File

@ -0,0 +1,120 @@
## Process this file with autoconf to produce configure.
## In general, the safest way to proceed is to run the following:
## % aclocal -I . -I `pwd`/../autoconf && autoheader && autoconf && automake
# make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57)
AC_INIT(glog, 0.1, opensource@google.com)
# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(src/config.h)
# Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_CXX
AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
AC_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)
# Check whether some low-level functions/files are available
AC_HEADER_STDC
# These are tested for by AC_HEADER_STDC, but I check again to set the var
AC_CHECK_HEADER(stdint.h, ac_cv_have_stdint_h=1, ac_cv_have_stdint_h=0)
AC_CHECK_HEADER(sys/types.h, ac_cv_have_systypes_h=1, ac_cv_have_systypes_h=0)
AC_CHECK_HEADER(inttypes.h, ac_cv_have_inttypes_h=1, ac_cv_have_inttypes_h=0)
AC_CHECK_HEADERS(syscall.h)
AC_CHECK_HEADERS(sys/syscall.h)
# For backtrace with glibc.
# TODO(hamaji): Support other platforms using libgcc.
AC_CHECK_HEADERS(execinfo.h)
AC_CHECK_SIZEOF(void *)
# These are the types I need. We look for them in either stdint.h,
# sys/types.h, or inttypes.h, all of which are part of the default-includes.
AC_CHECK_TYPE(uint16_t, ac_cv_have_uint16_t=1, ac_cv_have_uint16_t=0)
AC_CHECK_TYPE(u_int16_t, ac_cv_have_u_int16_t=1, ac_cv_have_u_int16_t=0)
AC_CHECK_TYPE(__uint16, ac_cv_have___uint16=1, ac_cv_have___uint16=0)
AC_CHECK_FUNC(sigaltstack,
AC_DEFINE(HAVE_SIGALTSTACK, 1,
[Define if you have the `sigaltstack' function]))
AX_C___ATTRIBUTE__
# We only care about these two attributes.
if test x"$ac_cv___attribute__" = x"yes"; then
ac_cv___attribute___noreturn="__attribute__ ((noreturn))"
ac_cv___attribute___printf_4_5="__attribute__((__format__ (__printf__, 4, 5)))"
else
ac_cv___attribute___noreturn=
ac_cv___attribute___printf_4_5=
fi
AX_C___BUILTIN_EXPECT
if test x"$ac_cv___builtin_expect" = x"yes"; then
ac_cv_have___builtin_expect=1
else
ac_cv_have___builtin_expect=0
fi
# On x86_64, instead of libunwind, we can choose to compile with frame-pointers
# (This isn't needed on i386, where -fno-omit-frame-pointer is the default).
AC_ARG_ENABLE(frame_pointers,
AS_HELP_STRING([--enable-frame-pointers],
[On x86_64 systems, compile with -fno-omit-frame-pointer (see INSTALL)]),
enable_frame_pointers=no)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [return __x86_64__ == 1 ? 0 : 1])],
[is_x86_64=yes], [is_x86_64=no])
AM_CONDITIONAL(ENABLE_FRAME_POINTERS, test "$enable_frame_pointers" = yes)
AM_CONDITIONAL(X86_64, test "$is_x86_64" = yes)
# Some of the code in this directory depends on pthreads
ACX_PTHREAD
# Check if there is google-gflags library installed.
AC_CHECK_LIB(gflags, main, ac_cv_have_libgflags=1, ac_cv_have_libgflags=0)
if test x"$ac_cv_have_libgflags" = x"1"; then
GFLAGS_LIBS=-lgflags
AC_DEFINE(HAVE_LIB_GFLAGS, 1, [define if you have google gflags library])
else
GFLAGS_LIBS=
fi
# We'd like to use read/write locks in several places in the code.
# See if our pthreads support extends to that. Note: for linux, it
# does as long as you define _XOPEN_SOURCE appropriately.
AC_RWLOCK
# Find out what namespace 'normal' STL code lives in, and also what namespace
# the user wants our classes to be defined in
AC_CXX_STL_NAMESPACE
AC_DEFINE_GOOGLE_NAMESPACE(google)
AC_CXX_USING_OPERATOR
# These are what's needed by logging.h.in and raw_logging.h.in
AC_SUBST(ac_google_start_namespace)
AC_SUBST(ac_google_end_namespace)
AC_SUBST(ac_google_namespace)
AC_SUBST(ac_cv_cxx_using_operator)
AC_SUBST(ac_cv___attribute___noreturn)
AC_SUBST(ac_cv___attribute___printf_4_5)
AC_SUBST(ac_cv_have___builtin_expect)
AC_SUBST(ac_cv_have_stdint_h)
AC_SUBST(ac_cv_have_systypes_h)
AC_SUBST(ac_cv_have_inttypes_h)
AC_SUBST(ac_cv_have_uint16_t)
AC_SUBST(ac_cv_have_u_int16_t)
AC_SUBST(ac_cv_have___uint16)
AC_SUBST(ac_cv_have_libgflags)
AC_SUBST(GFLAGS_LIBS)
# Write generated configuration file
AC_CONFIG_FILES([Makefile src/glog/logging.h src/glog/raw_logging.h src/glog/vlog_is_on.h src/glog/stl_logging.h])
AC_OUTPUT

530
depcomp Executable file
View File

@ -0,0 +1,530 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2005-07-09.11
# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by `PROGRAMS ARGS'.
object Object file output by `PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputing dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> $depfile
echo >> $depfile
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> $depfile
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts `$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
tmpdepfile="$stripped.u"
if test "$libtool" = yes; then
"$@" -Wc,-M
else
"$@" -M
fi
stat=$?
if test -f "$tmpdepfile"; then :
else
stripped=`echo "$stripped" | sed 's,^.*/,,'`
tmpdepfile="$stripped.u"
fi
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
if test -f "$tmpdepfile"; then
outname="$stripped.o"
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
# With Tru64 cc, shared objects can also be used to make a
# static library. This mecanism is used in libtool 1.4 series to
# handle both shared and static libraries in a single compilation.
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
#
# With libtool 1.5 this exception was removed, and libtool now
# generates 2 separate objects for the 2 libraries. These two
# compilations output dependencies in in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
tmpdepfile2=$dir$base.o.d # libtool 1.5
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.o.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
tmpdepfile4=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no
for arg in "$@"; do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix="`echo $object | sed 's/^.*\././'`"
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
"$@" || exit $?
IFS=" "
for arg
do
case "$arg" in
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

115
doc/designstyle.css Normal file
View File

@ -0,0 +1,115 @@
body {
background-color: #ffffff;
color: black;
margin-right: 1in;
margin-left: 1in;
}
h1, h2, h3, h4, h5, h6 {
color: #3366ff;
font-family: sans-serif;
}
@media print {
/* Darker version for printing */
h1, h2, h3, h4, h5, h6 {
color: #000080;
font-family: helvetica, sans-serif;
}
}
h1 {
text-align: center;
font-size: 18pt;
}
h2 {
margin-left: -0.5in;
}
h3 {
margin-left: -0.25in;
}
h4 {
margin-left: -0.125in;
}
hr {
margin-left: -1in;
}
/* Definition lists: definition term bold */
dt {
font-weight: bold;
}
address {
text-align: right;
}
/* Use the <code> tag for bits of code and <var> for variables and objects. */
code,pre,samp,var {
color: #006000;
}
/* Use the <file> tag for file and directory paths and names. */
file {
color: #905050;
font-family: monospace;
}
/* Use the <kbd> tag for stuff the user should type. */
kbd {
color: #600000;
}
div.note p {
float: right;
width: 3in;
margin-right: 0%;
padding: 1px;
border: 2px solid #6060a0;
background-color: #fffff0;
}
UL.nobullets {
list-style-type: none;
list-style-image: none;
margin-left: -1em;
}
/*
body:after {
content: "Google Confidential";
}
*/
/* pretty printing styles. See prettify.js */
.str { color: #080; }
.kwd { color: #008; }
.com { color: #800; }
.typ { color: #606; }
.lit { color: #066; }
.pun { color: #660; }
.pln { color: #000; }
.tag { color: #008; }
.atn { color: #606; }
.atv { color: #080; }
pre.prettyprint { padding: 2px; border: 1px solid #888; }
.embsrc { background: #eee; }
@media print {
.str { color: #060; }
.kwd { color: #006; font-weight: bold; }
.com { color: #600; font-style: italic; }
.typ { color: #404; font-weight: bold; }
.lit { color: #044; }
.pun { color: #440; }
.pln { color: #000; }
.tag { color: #006; font-weight: bold; }
.atn { color: #404; }
.atv { color: #060; }
}
/* Table Column Headers */
.hdr {
color: #006;
font-weight: bold;
background-color: #dddddd; }
.hdr2 {
color: #006;
background-color: #eeeeee; }

506
doc/glog.html Normal file
View File

@ -0,0 +1,506 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>How To Use Google Logging Library (glog)</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="http://www.google.com/favicon.ico" type="image/x-icon"
rel="shortcut icon">
<link href="designstyle.css" type="text/css" rel="stylesheet">
<style type="text/css">
<!--
ol.bluelist li {
color: #3366ff;
font-family: sans-serif;
}
ol.bluelist li p {
color: #000;
font-family: "Times Roman", times, serif;
}
ul.blacklist li {
color: #000;
font-family: "Times Roman", times, serif;
}
//-->
</style>
</head>
<body>
<h1>How To Use Google Logging Library (glog)</h1>
<small>(as of
<script type=text/javascript>
var lm = new Date(document.lastModified);
document.write(lm.toDateString());
</script>)
</small>
<br>
<h2> <A NAME=intro>Introduction</A> </h2>
<p><b>Google glog</b> is a library that implements application-level
logging. This library provides logging APIs based on C++-style
streams and various helper macros.
You can log a message by simply streaming things to LOG(&lt;a
particular <a href="#severity">severity level</a>&gt;), e.g.
<pre>
#include &lt;google/logging.h&gt;
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
// ...
LOG(INFO) &lt;&lt; "Found " &lt;&lt; num_cookies &lt;&lt; " cookies";
}
</pre>
<p>Google 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, and more. This document describes the
functionality supported by glog. Please note that this document
doesn't describe all features in this library, but the most useful
ones. If you want to find less common features, please check
header files under <code>src/google</code> directory.
<h2> <A NAME=severity>Severity Level</A> </h2>
<p>
You can specify one of the following severity levels (in
increasing order of severity): <code>INFO</code>, <code>WARNING</code>,
<code>ERROR</code>, and <code>FATAL</code>.
Logging a <code>FATAL</code> 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 <code>FATAL</code> will be logged to the
logfiles of severity <code>FATAL</code>, <code>ERROR</code>,
<code>WARNING</code>, and <code>INFO</code>.
<p>
The <code>DFATAL</code> severity logs a <code>FATAL</code> error in
debug mode (i.e., there is no <code>NDEBUG</code> macro defined), but
avoids halting the program in production by automatically reducing the
severity to <code>ERROR</code>.
<p>Unless otherwise specified, glog writes to the filename
"/tmp/&lt;program name&gt;.&lt;hostname&gt;.&lt;user name&gt;.log.&lt;severity level&gt;.&lt;date&gt;.&lt;time&gt;.&lt;pid&gt;"
(e.g., "/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474").
By default, glog copies the log messages of severity level
<code>ERROR</code> or <code>FATAL</code> to standard error (stderr)
in addition to log files.
<h2><A NAME=flags>Setting Flags</A></h2>
<p>Several flags influences glog's output behavior.
If the <a href="http://code.google.com/p/google-gflags/">Google
gflags library</a> is installed on your machine, the
<code>configure</code> script (see the INSTALL file in the package for
detail of this script) will automatically detect and use it,
allowing you to pass flags on the command line. For example, if you
want to turn the flag <code>--logtostderr</code> on, you can start
your application with the following command line:
<pre>
./your_application --logtostderr=1
</pre>
If the Google gflags library isn't installed, you set flags via
environment variables, prefixing the flag name with "GLOG_", e.g.
<pre>
GLOG_logtostderr=1 ./your_application
</pre>
<p>The following flags are most commonly used:
<dl>
<dt><code>logtostderr</code> (<code>bool</code>, default=<code>false</code>)
<dd>Log messages to stderr instead of logfiles.<br>
Note: you can set binary flags to <code>true</code> by specifying
<code>1</code>, <code>true</code> , or <code>yes</code> (case
insensitive).
Also, you can set binary flags to <code>false</code> by specifying
<code>0</code>, <code>false</code>, or <code>no</code> (again, case
insensitive).
<dt><code>stderrthreshold</code> (<code>int</code>, default=2, which
is <code>ERROR</code>)
<dd>Copy log messages at or above this level to stderr in
addition to logfiles. The numbers of severity levels
<code>INFO</code>, <code>WARNING</code>, <code>ERROR</code>, and
<code>FATAL</code> are 0, 1, 2, and 3, respectively.
<dt><code>minloglevel</code> (<code>int</code>, default=0, which
is <code>INFO</code>)
<dd>Log messages at or above this level. Again, the numbers of
severity levels <code>INFO</code>, <code>WARNING</code>,
<code>ERROR</code>, and <code>FATAL</code> are 0, 1, 2, and 3,
respectively.
<dt><code>log_dir</code> (<code>string</code>, default="")
<dd>If specified, logfiles are written into this directory instead
of the default logging directory.
<dt><code>v</code> (<code>int</code>, default=0)
<dd>Show all <code>VLOG(m)</code> messages for <code>m</code> less or
equal the value of this flag. Overridable by --vmodule.
See <a href="#verbose">the section about verbose logging</a> for more
detail.
<dt><code>vmodule</code> (<code>string</code>, default="")
<dd>Per-module verbose level. The argument has to contain a
comma-separated list of &lt;module name&gt;=&lt;log level&gt;.
&lt;module name&gt;
is a glob pattern (e.g., <code>gfs*</code> for all modules whose name
starts with "gfs"), matched against the filename base
(that is, name ignoring .cc/.h./-inl.h).
&lt;log level&gt; overrides any value given by --v.
See also <a href="#verbose">the section about verbose logging</a>.
</dl>
<p>There are some other flags defined in logging.cc. Please grep the
source code for "DEFINE_" to see a complete list of all flags.
<h2><A NAME=conditional>Conditional / Occasional Logging</A></h2>
<p>Sometimes, you may only want to log a message under certain
conditions. You can use the following macros to perform conditional
logging:
<pre>
LOG_IF(INFO, num_cookies > 10) &lt;&lt; "Got lots of cookies";
</pre>
The "Got lots of cookies" message is logged only when the variable
<code>num_cookies</code> 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.
<pre>
LOG_EVERY_N(INFO, 10) &lt;&lt; "Got the " &lt;&lt; COUNTER &lt;&lt; "th cookie";
</pre>
<p>The above line outputs a log messages on the 1st, 11th,
21st, ... times it is executed. Note that the special
<code>COUNTER</code> value is used to identify which repetition is
happening.
<p>You can combine conditional and occasional logging with the
following macro.
<pre>
LOG_IF_EVERY_N(INFO, (size > 1024), 10) &lt;&lt; "Got the " &lt;&lt; COUNTER
&lt;&lt; "th big cookie";
</pre>
<p>Instead of outputting a message every nth time, you can also limit
the output to the first n occurrences:
<pre>
LOG_FIRST_N(INFO, 20) &lt;&lt; "Got the " &lt;&lt; COUNTER &lt;&lt; "th cookie";
</pre>
<p>Outputs log messages for the first 20 times it is executed. Again,
the <code>COUNTER</code> identifier indicates which repetition is
happening.
<h2><A NAME=debug>Debug Mode Support</A></h2>
<p>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.
<pre>
DLOG(INFO) &lt;&lt; "Found cookies";
DLOG_IF(INFO, num_cookies > 10) &lt;&lt; "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) &lt;&lt; "Got the " &lt;&lt; COUNTER &lt;&lt; "th cookie";
</pre>
<p>All "debug mode" logging is compiled away to nothing for non-debug mode
compiles.
<h2><A NAME=check>CHECK Macros</A></h2>
<p>It is a good practice to check expected conditions in your program
frequently to detect errors as early as possible. The
<code>CHECK</code> macro provides the ability to abort the application
when a condition is not met, similar to the <code>assert</code> macro
defined in the standard C library.
<p><code>CHECK</code> aborts the application if a condition is not
true. Unlike <code>assert</code>, it is *not* controlled by
<code>NDEBUG</code>, so the check will be executed regardless of
compilation mode. Therefore, <code>fp->Write(x)</code> in the
following example is always executed:
<pre>
CHECK(fp->Write(x) == 4) &lt;&lt; "Write failed!";
</pre>
<p>There are various helper macros for
equality/inequality checks - <code>CHECK_EQ</code>,
<code>CHECK_NE</code>, <code>CHECK_LE</code>, <code>CHECK_LT</code>,
<code>CHECK_GE</code>, and <code>CHECK_GT</code>.
They compare two values, and log a
<code>FATAL</code> message including the two values when the result is
not as expected. The values must have <code>operator&lt;&lt;(ostream,
...)</code> defined.
<p>You may append to the error message like so:
<pre>
CHECK_NE(1, 2) &lt;&lt; ": The world must be ending!";
</pre>
<p>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:
<pre>
CHECK_EQ(string("abc")[1], 'b');
</pre>
<p>The compiler reports an error if one of the arguments is a
pointer and the other is NULL. To work around this, simply static_cast
NULL to the type of the desired pointer.
<pre>
CHECK_EQ(some_ptr, static_cast<SomeType*>(NULL));
</pre>
<p>Better yet, use the CHECK_NOTNULL macro:
<pre>
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
</pre>
<p>Since this macro returns the given pointer, this is very useful in
constructor initializer lists.
<pre>
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
</pre>
<p>Note that you cannot use this macro as a C++ stream due to this
feature. Please use <code>CHECK_EQ</code> described above to log a
custom message before aborting the application.
<p>If you are comparing C strings (char *), a handy set of macros
performs case sensitive as well as case insensitive comparisons -
<code>CHECK_STREQ</code>, <code>CHECK_STRNE</code>,
<code>CHECK_STRCASEEQ</code>, and <code>CHECK_STRCASENE</code>. The
CASE versions are case-insensitive. You can safely pass <code>NULL</code>
pointers for this macro. They treat <code>NULL</code> and any
non-<code>NULL</code> string as not equal. Two <code>NULL</code>s are
equal.
<p>Note that both arguments may be temporary strings which are
destructed at the end of the current "full expression"
(e.g., <code>CHECK_STREQ(Foo().c_str(), Bar().c_str())</code> where
<code>Foo</code> and <code>Bar</code> returns C++'s
<code>std::string</code>).
<p>The <code>CHECK_DOUBLE_EQ</code> macro checks the equality of two
floating point values, accepting a small error margin.
<code>CHECK_NEAR</code> accepts a third floating point argument, which
specifies the acceptable error margin.
<h2><A NAME=verbose>Verbose Logging</A></h2>
<p>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
<code>VLOG</code> macro, which allows you to define your own numeric
logging levels. The <code>--v</code> command line option controls
which verbose messages are logged:
<pre>
VLOG(1) &lt;&lt; "I'm printed when you run the program with --v=1 or higher";
VLOG(2) &lt;&lt; "I'm printed when you run the program with --v=2 or higher";
</pre>
<p>With <code>VLOG</code>, the lower the verbose level, the more
likely messages are to be logged. For example, if
<code>--v==1</code>, <code>VLOG(1)</code> will log, but
<code>VLOG(2)</code> will not log. This is opposite of the severity
level, where <code>INFO</code> is 0, and <code>ERROR</code> is 2.
<code>--minloglevel</code> of 1 will log <code>WARNING</code> and
above. Though you can specify any integers for both <code>VLOG</code>
macro and <code>--v</code> flag, the common values for them are small
positive integers. For example, if you write <code>VLOG(0)</code>,
you should specify <code>--v=-1</code> or lower to silence it. This
is less useful since we may not want verbose logs by default in most
cases. The <code>VLOG</code> macros always log at the
<code>INFO</code> log level (when they log at all).
<p>Verbose logging can be controlled from the command line on a
per-module basis:
<pre>
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
</pre>
<p>will:
<ul>
<li>a. Print VLOG(2) and lower messages from mapreduce.{h,cc}
<li>b. Print VLOG(1) and lower messages from file.{h,cc}
<li>c. Print VLOG(3) and lower messages from files prefixed with "gfs"
<li>d. Print VLOG(0) and lower messages from elsewhere
</ul>
<p>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 <a
href="#flags">command line flags</a>.
<p>There's also <code>VLOG_IS_ON(n)</code> "verbose level" condition
macro. This macro returns true when the <code>--v</code> is equal or
greater than <code>n</code>. To be used as
<pre>
if (VLOG_IS_ON(2)) {
// do some logging preparation and logging
// that can't be accomplished with just VLOG(2) &lt;&lt; ...;
}
</pre>
<p>Verbose level condition macros <code>VLOG_IF</code>,
<code>VLOG_EVERY_N</code> and <code>VLOG_IF_EVERY_N</code> behave
analogous to <code>LOG_IF</code>, <code>LOG_EVERY_N</code>,
<code>LOF_IF_EVERY</code>, but accept a numeric verbosity level as
opposed to a severity level.
<pre>
VLOG_IF(1, (size > 1024))
&lt;&lt; "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)
&lt;&lt; "I'm printed every 10th occurrence, and when you run the program "
"with --v=1 or more. Present occurence is " &lt;&lt; COUNTER;
VLOG_IF_EVERY_N(1, (size > 1024), 10)
&lt;&lt; "I'm printed on every 10th occurence of case when size is more "
" than 1024, when you run the program with --v=1 or more. ";
"Present occurence is " &lt;&lt; COUNTER;
</pre>
<h2> <A name="misc">Miscellaneous Notes</A> </h2>
<h3><A NAME=message>Performance of Messages</A></h3>
<p>The conditional logging macros provided by glog (e.g.,
<code>CHECK</code>, <code>LOG_IF</code>, <code>VLOG</code>, ...) 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.
<pre>
CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
</pre>
<h3><A NAME=failure>User-defined Failure Function</A></h3>
<p><code>FATAL</code> severity level messages or unsatisfied
<code>CHECK</code> condition terminate your program. You can change
the behavior of the termination by
<code>InstallFailureFunction</code>.
<pre>
void YourFailureFunction() {
// Reports something...
exit(1);
}
int main(int argc, char* argv[]) {
google::InstallFailureFunction(&amp;YourFailureFunction);
}
</pre>
<p>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).
<h3><A NAME=raw>Raw Logging</A></h3>
<p>The header file <code>&lt;google/raw_logging.h&gt;</code> 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 <code>src/google/raw_logging.h.in</code> for detail.
</p>
<h3><A NAME=plog>Google Style perror()</A></h3>
<p><code>PLOG()</code> and <code>PLOG_IF()</code> and
<code>PCHECK()</code> behave exactly like their <code>LOG*</code> and
<code>CHECK</code> equivalents with the addition that they append a
description of the current state of errno to their output lines.
E.g.
<pre>
PCHECK(write(1, NULL, 2) >= 0) << "Write NULL failed";
</pre>
<p>This check fails with the following error message.
<pre>
F0825 185142 test.cc:22] Check failed: write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]
</pre>
<h3><A NAME=syslog>Syslog</A></h3>
<p><code>SYSLOG</code>, <code>SYSLOG_IF</code>, and
<code>SYSLOG_EVERY_N</code> 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.
<h3><A NAME=strip>Strip Logging Messages</A></h3>
<p>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:
<p>If your application has code like this:
<pre>
#define GOOGLE_STRIP_LOG 1 // this must go before the #include!
#include &lt;google/logging.h&gt;
</pre>
<p>The compiler will remove the log messages whose severity are less
than the specified integer value. Since
<code>VLOG</code> logs at the severity level <code>INFO</code>
(numeric value <code>0</code>),
setting <code>GOOGLE_STRIP_LOG</code> to 1 or greater removes
all log messages associated with <code>VLOG</code>s as well as
<code>INFO</code> log statements.
<hr>
<address>
Shinichiro Hamaji<br>
Gregor Hohpe<br>
<script type=text/javascript>
var lm = new Date(document.lastModified);
document.write(lm.toDateString());
</script>
</address>
</body>
</html>

323
install-sh Executable file
View File

@ -0,0 +1,323 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2005-05-14.22
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
chmodcmd="$chmodprog 0755"
chowncmd=
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dstarg=
no_target_directory=
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test -n "$1"; do
case $1 in
-c) shift
continue;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-s) stripcmd=$stripprog
shift
continue;;
-t) dstarg=$2
shift
shift
continue;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
*) # When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
test -n "$dir_arg$dstarg" && break
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dstarg=$arg
done
break;;
esac
done
if test -z "$1"; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
for src
do
# Protect names starting with `-'.
case $src in
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
dst=$src
src=
if test -d "$dst"; then
mkdircmd=:
chmodcmd=
else
mkdircmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dst=$dst/`basename "$src"`
fi
fi
# This sed command emulates the dirname command.
dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# Skip lots of stat calls in the usual case.
if test ! -d "$dstdir"; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
oIFS=$IFS
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
shift
IFS=$oIFS
pathcomp=
while test $# -ne 0 ; do
pathcomp=$pathcomp$1
shift
if test ! -d "$pathcomp"; then
$mkdirprog "$pathcomp"
# mkdir can fail with a `File exist' error in case several
# install-sh are creating the directory concurrently. This
# is OK.
test -d "$pathcomp" || exit
fi
pathcomp=$pathcomp/
done
fi
if test -n "$dir_arg"; then
$doit $mkdircmd "$dst" \
&& { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
else
dstfile=`basename "$dst"`
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
trap '(exit $?); exit' 1 2 13 15
# Copy the file name to the temp name.
$doit $cpprog "$src" "$dsttmp" &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dstdir/$dstfile"; then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
|| $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
|| {
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
}
}
fi || { (exit 1); exit 1; }
done
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit 0
}
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

6871
ltmain.sh Normal file

File diff suppressed because it is too large Load Diff

16
m4/ac_have_attribute.m4 Normal file
View File

@ -0,0 +1,16 @@
AC_DEFUN([AX_C___ATTRIBUTE__], [
AC_MSG_CHECKING(for __attribute__)
AC_CACHE_VAL(ac_cv___attribute__, [
AC_TRY_COMPILE(
[#include <stdlib.h>
static void foo(void) __attribute__ ((unused));
void foo(void) { exit(1); }],
[],
ac_cv___attribute__=yes,
ac_cv___attribute__=no
)])
if test "$ac_cv___attribute__" = "yes"; then
AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__])
fi
AC_MSG_RESULT($ac_cv___attribute__)
])

View File

@ -0,0 +1,14 @@
AC_DEFUN([AX_C___BUILTIN_EXPECT], [
AC_MSG_CHECKING(for __builtin_expect)
AC_CACHE_VAL(ac_cv___builtin_expect, [
AC_TRY_COMPILE(
[int foo(void) { if (__builtin_expect(0, 0)) return 1; return 0; }],
[],
ac_cv___builtin_expect=yes,
ac_cv___builtin_expect=no
)])
if test "$ac_cv___builtin_expect" = "yes"; then
AC_DEFINE(HAVE___BUILTIN_EXPECT, 1, [define if your compiler has __builtin_expect])
fi
AC_MSG_RESULT($ac_cv___builtin_expect)
])

31
m4/ac_rwlock.m4 Normal file
View File

@ -0,0 +1,31 @@
# TODO(csilvers): it would be better to actually try to link against
# -pthreads, to make sure it defines these methods, but that may be
# too hard, since pthread support is really tricky.
# Check for support for pthread_rwlock_init() etc.
# These aren't posix, but are widely supported. To get them on linux,
# you need to define _XOPEN_SOURCE first, so this check assumes your
# application does that.
#
# Note: OS X (as of 6/1/06) seems to support pthread_rwlock, but
# doesn't define PTHREAD_RWLOCK_INITIALIZER. Therefore, we don't test
# that particularly macro. It's probably best if you don't use that
# macro in your code either.
AC_DEFUN([AC_RWLOCK],
[AC_CACHE_CHECK(support for pthread_rwlock_* functions,
ac_rwlock,
[AC_LANG_SAVE
AC_LANG_C
AC_TRY_COMPILE([#define _XOPEN_SOURCE 500
#include <pthread.h>],
[pthread_rwlock_t l; pthread_rwlock_init(&l, NULL);
pthread_rwlock_rdlock(&l);
return 0;],
ac_rwlock=yes, ac_rwlock=no)
AC_LANG_RESTORE
])
if test "$ac_rwlock" = yes; then
AC_DEFINE(HAVE_RWLOCK,1,[define if the compiler implements pthread_rwlock_*])
fi
])

353
m4/acx_pthread.m4 Normal file
View File

@ -0,0 +1,353 @@
# This was retrieved from
# http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/common/acx_pthread.m4?rev=1227
# See also (perhaps for new versions?)
# http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/common/acx_pthread.m4
dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
dnl
dnl @summary figure out how to build C programs using POSIX threads
dnl
dnl This macro figures out how to build C programs using POSIX threads.
dnl It sets the PTHREAD_LIBS output variable to the threads library and
dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
dnl C compiler flags that are needed. (The user can also force certain
dnl compiler flags/libs to be tested by setting these environment
dnl variables.)
dnl
dnl Also sets PTHREAD_CC to any special C compiler that is needed for
dnl multi-threaded programs (defaults to the value of CC otherwise).
dnl (This is necessary on AIX to use the special cc_r compiler alias.)
dnl
dnl NOTE: You are assumed to not only compile your program with these
dnl flags, but also link it with them as well. e.g. you should link
dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
dnl $LIBS
dnl
dnl If you are only building threads programs, you may wish to use
dnl these variables in your default LIBS, CFLAGS, and CC:
dnl
dnl LIBS="$PTHREAD_LIBS $LIBS"
dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
dnl CC="$PTHREAD_CC"
dnl
dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
dnl
dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
dnl default action will define HAVE_PTHREAD.
dnl
dnl Please let the authors know if this macro fails on any platform, or
dnl if you have any other suggestions or comments. This macro was based
dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
dnl We are also grateful for the helpful feedback of numerous users.
dnl
dnl @category InstalledPackages
dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
dnl @version 2006-05-29
dnl @license GPLWithACException
dnl
dnl Checks for GCC shared/pthread inconsistency based on work by
dnl Marcin Owsiany <marcin@owsiany.pl>
AC_DEFUN([ACX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
acx_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
AC_MSG_RESULT($acx_pthread_ok)
if test x"$acx_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
;;
esac
if test x"$acx_pthread_ok" = xno; then
for flag in $acx_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
if test x"$acx_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[acx_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($acx_pthread_ok)
if test "x$acx_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$acx_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
[attr_name=$attr; break])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
# The next part tries to detect GCC inconsistency with -shared on some
# architectures and systems. The problem is that in certain
# configurations, when -shared is specified, GCC "forgets" to
# internally use various flags which are still necessary.
AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies])
check_inconsistencies=yes
case "${host_cpu}-${host_os}" in
*-darwin*) check_inconsistencies=no ;;
esac
if test x"$GCC" != xyes -o "x$check_inconsistencies" != xyes ; then
AC_MSG_RESULT([no])
else
AC_MSG_RESULT([yes])
# In order not to create several levels of indentation, we test
# the value of "$ok" until we find out the cure or run out of
# ideas.
ok="no"
#
# Prepare the flags
#
save_CFLAGS="$CFLAGS"
save_LIBS="$LIBS"
save_CC="$CC"
# Try with the flags determined by the earlier checks.
#
# -Wl,-z,defs forces link-time symbol resolution, so that the
# linking checks with -shared actually have any value
#
# FIXME: -fPIC is required for -shared on many architectures,
# so we specify it here, but the right way would probably be to
# properly detect whether it is actually required.
CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CC="$PTHREAD_CC"
AC_MSG_CHECKING([whether -pthread is sufficient with -shared])
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
#
# Linux gcc on some architectures such as mips/mipsel forgets
# about -lpthread
#
if test x"$ok" = xno; then
AC_MSG_CHECKING([whether -lpthread fixes that])
LIBS="-lpthread $PTHREAD_LIBS $save_LIBS"
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
else
AC_MSG_RESULT([no])
fi
fi
#
# FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc
#
if test x"$ok" = xno; then
AC_MSG_CHECKING([whether -lc_r fixes that])
LIBS="-lc_r $PTHREAD_LIBS $save_LIBS"
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
else
AC_MSG_RESULT([no])
fi
fi
if test x"$ok" = xno; then
# OK, we have run out of ideas
AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries])
# so it's not safe to assume that we may use pthreads
acx_pthread_ok=no
fi
CFLAGS="$save_CFLAGS"
LIBS="$save_LIBS"
CC="$save_CC"
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
acx_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl ACX_PTHREAD

36
m4/google_namespace.m4 Normal file
View File

@ -0,0 +1,36 @@
# Allow users to override the namespace we define our application's classes in
# Arg $1 is the default namespace to use if --enable-namespace isn't present.
# In general, $1 should be 'google', so we put all our exported symbols in a
# unique namespace that is not likely to conflict with anyone else. However,
# when it makes sense -- for instance, when publishing stl-like code -- you
# may want to go with a different default, like 'std'.
AC_DEFUN([AC_DEFINE_GOOGLE_NAMESPACE],
[google_namespace_default=[$1]
AC_ARG_ENABLE(namespace, [ --enable-namespace=FOO to define these Google
classes in the FOO namespace. --disable-namespace
to define them in the global namespace. Default
is to define them in namespace $1.],
[case "$enableval" in
yes) google_namespace="$google_namespace_default" ;;
no) google_namespace="" ;;
*) google_namespace="$enableval" ;;
esac],
[google_namespace="$google_namespace_default"])
if test -n "$google_namespace"; then
ac_google_namespace="$google_namespace"
ac_google_start_namespace="namespace $google_namespace {"
ac_google_end_namespace="}"
else
ac_google_namespace=""
ac_google_start_namespace=""
ac_google_end_namespace=""
fi
AC_DEFINE_UNQUOTED(GOOGLE_NAMESPACE, $ac_google_namespace,
Namespace for Google classes)
AC_DEFINE_UNQUOTED(_START_GOOGLE_NAMESPACE_, $ac_google_start_namespace,
Puts following code inside the Google namespace)
AC_DEFINE_UNQUOTED(_END_GOOGLE_NAMESPACE_, $ac_google_end_namespace,
Stops putting the code inside the Google namespace)
])

15
m4/namespaces.m4 Normal file
View File

@ -0,0 +1,15 @@
# Checks whether the compiler implements namespaces
AC_DEFUN([AC_CXX_NAMESPACES],
[AC_CACHE_CHECK(whether the compiler implements namespaces,
ac_cv_cxx_namespaces,
[AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_COMPILE([namespace Outer {
namespace Inner { int i = 0; }}],
[using namespace Outer::Inner; return i;],
ac_cv_cxx_namespaces=yes,
ac_cv_cxx_namespaces=no)
AC_LANG_RESTORE])
if test "$ac_cv_cxx_namespaces" = yes; then
AC_DEFINE(HAVE_NAMESPACES, 1, [define if the compiler implements namespaces])
fi])

25
m4/stl_namespace.m4 Normal file
View File

@ -0,0 +1,25 @@
# We check what namespace stl code like vector expects to be executed in
AC_DEFUN([AC_CXX_STL_NAMESPACE],
[AC_CACHE_CHECK(
what namespace STL code is in,
ac_cv_cxx_stl_namespace,
[AC_REQUIRE([AC_CXX_NAMESPACES])
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_COMPILE([#include <vector>],
[vector<int> t; return 0;],
ac_cv_cxx_stl_namespace=none)
AC_TRY_COMPILE([#include <vector>],
[std::vector<int> t; return 0;],
ac_cv_cxx_stl_namespace=std)
AC_LANG_RESTORE])
if test "$ac_cv_cxx_stl_namespace" = none; then
AC_DEFINE(STL_NAMESPACE,,
[the namespace where STL code like vector<> is defined])
fi
if test "$ac_cv_cxx_stl_namespace" = std; then
AC_DEFINE(STL_NAMESPACE,std,
[the namespace where STL code like vector<> is defined])
fi
])

15
m4/using_operator.m4 Normal file
View File

@ -0,0 +1,15 @@
AC_DEFUN([AC_CXX_USING_OPERATOR],
[AC_CACHE_CHECK(
whether compiler supports using ::operator<<,
ac_cv_cxx_using_operator,
[AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_COMPILE([#include <iostream>
std::ostream& operator<<(std::ostream&, struct s);],
[using ::operator<<; return 0;],
ac_cv_cxx_using_operator=1,
ac_cv_cxx_using_operator=0)
AC_LANG_RESTORE])
if test "$ac_cv_cxx_using_operator" = 1; then
AC_DEFINE(HAVE_USING_OPERATOR, 1, [define if the compiler supports using expression for operator])
fi])

360
missing Executable file
View File

@ -0,0 +1,360 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2005-06-08.21
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
# Now exit if we have it, but it failed. Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program).
case "$1" in
lex|yacc)
# Not GNU programs, they don't have --version.
;;
tar)
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
exit 1
fi
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
# Could not run --version or --help. This is probably someone
# running `$TOOL --version' or `$TOOL --help' to check whether
# $TOOL exists and not knowing $TOOL uses missing.
exit 1
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
aclocal*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case "$f" in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te)
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if [ ! -f y.tab.h ]; then
echo >y.tab.h
fi
if [ ! -f y.tab.c ]; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex|flex)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if [ ! -f lex.yy.c ]; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
# The file to touch is that specified with -o ...
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
# ... or it is the one specified with @setfilename ...
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
# ... or it is derived from the source name (dir/f.texi becomes f.info)
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
fi
# If the file does not exist, the user really needs makeinfo;
# let's fail without touching anything.
test -f $file || exit 1
touch $file
;;
tar)
shift
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

158
mkinstalldirs Executable file
View File

@ -0,0 +1,158 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
scriptversion=2005-06-29.22
# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-05-16
# Public domain.
#
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
errstatus=0
dirmode=
usage="\
Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
Create each directory DIR (with mode MODE, if specified), including all
leading file name components.
Report bugs to <bug-automake@gnu.org>."
# process command line arguments
while test $# -gt 0 ; do
case $1 in
-h | --help | --h*) # -h for help
echo "$usage"
exit $?
;;
-m) # -m PERM arg
shift
test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
dirmode=$1
shift
;;
--version)
echo "$0 $scriptversion"
exit $?
;;
--) # stop option processing
shift
break
;;
-*) # unknown option
echo "$usage" 1>&2
exit 1
;;
*) # first non-opt arg
break
;;
esac
done
for file
do
if test -d "$file"; then
shift
else
break
fi
done
case $# in
0) exit 0 ;;
esac
# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and
# mkdir -p a/c at the same time, both will detect that a is missing,
# one will create a, then the other will try to create a and die with
# a "File exists" error. This is a problem when calling mkinstalldirs
# from a parallel make. We use --version in the probe to restrict
# ourselves to GNU mkdir, which is thread-safe.
case $dirmode in
'')
if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
echo "mkdir -p -- $*"
exec mkdir -p -- "$@"
else
# On NextStep and OpenStep, the `mkdir' command does not
# recognize any option. It will interpret all options as
# directories to create, and then abort because `.' already
# exists.
test -d ./-p && rmdir ./-p
test -d ./--version && rmdir ./--version
fi
;;
*)
if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
test ! -d ./--version; then
echo "mkdir -m $dirmode -p -- $*"
exec mkdir -m "$dirmode" -p -- "$@"
else
# Clean up after NextStep and OpenStep mkdir.
for d in ./-m ./-p ./--version "./$dirmode";
do
test -d $d && rmdir $d
done
fi
;;
esac
for file
do
case $file in
/*) pathcomp=/ ;;
*) pathcomp= ;;
esac
oIFS=$IFS
IFS=/
set fnord $file
shift
IFS=$oIFS
for d
do
test "x$d" = x && continue
pathcomp=$pathcomp$d
case $pathcomp in
-*) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp"
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
else
if test ! -z "$dirmode"; then
echo "chmod $dirmode $pathcomp"
lasterr=
chmod "$dirmode" "$pathcomp" || lasterr=$?
if test ! -z "$lasterr"; then
errstatus=$lasterr
fi
fi
fi
fi
pathcomp=$pathcomp/
done
done
exit $errstatus
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

70
packages/deb.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/bash -e
# This takes one commandline argument, the name of the package. If no
# name is given, then we'll end up just using the name associated with
# an arbitrary .tar.gz file in the rootdir. That's fine: there's probably
# only one.
#
# Run this from the 'packages' directory, just under rootdir
## Set LIB to lib if exporting a library, empty-string else
LIB=
#LIB=lib
PACKAGE="$1"
# We can only build Debian packages, if the Debian build tools are installed
if [ \! -x /usr/bin/debuild ]; then
echo "Cannot find /usr/bin/debuild. Not building Debian packages." 1>&2
exit 0
fi
# Double-check we're in the packages directory, just under rootdir
if [ \! -r ../Makefile -a \! -r ../INSTALL ]; then
echo "Must run $0 in the 'packages' directory, under the root directory." 1>&2
echo "Also, you must run \"make dist\" before running this script." 1>&2
exit 0
fi
# Find the top directory for this package
topdir="${PWD%/*}"
# Find the tar archive built by "make dist"
archive="$(basename "$(ls -1 ${topdir}/$PACKAGE*.tar.gz | tail -n 1)" .tar.gz)"
if [ -z "${archive}" ]; then
echo "Cannot find ../$PACKAGE*.tar.gz. Run \"make dist\" first." 1>&2
exit 0
fi
# Create a pristine directory for building the Debian package files
trap 'rm -rf '`pwd`/tmp'; exit $?' EXIT SIGHUP SIGINT SIGTERM
rm -rf tmp
mkdir -p tmp
cd tmp
# Debian has very specific requirements about the naming of build
# directories, and tar archives. It also wants to write all generated
# packages to the parent of the source directory. We accommodate these
# requirements by building directly from the tar file.
ln -s "${topdir}/${archive}.tar.gz" "${LIB}${archive}.orig.tar.gz"
tar zfx "${LIB}${archive}.orig.tar.gz"
[ -n "${LIB}" ] && mv "${archive}" "${LIB}${archive}"
cd "${LIB}${archive}"
# This is one of those 'specific requirements': where the deb control files live
ln -s "packages/deb" "debian"
# Now, we can call Debian's standard build tool
debuild -uc -us
cd ../.. # get back to the original top-level dir
# We'll put the result in a subdirectory that's named after the OS version
# we've made this .deb file for.
destdir="debian-$(cat /etc/debian_version 2>/dev/null || echo UNKNOWN)"
rm -rf "$destdir"
mkdir -p "$destdir"
mv $(find tmp -mindepth 1 -maxdepth 1 -type f) "$destdir"
echo
echo "The Debian package files are located in $PWD/$destdir"

7
packages/deb/README Normal file
View File

@ -0,0 +1,7 @@
The list of files here isn't complete. For a step-by-step guide on
how to set this package up correctly, check out
http://www.debian.org/doc/maint-guide/
Most of the files that are in this directory are boilerplate.
However, you may need to change the list of binary-arch dependencies
in 'rules'.

5
packages/deb/changelog Normal file
View File

@ -0,0 +1,5 @@
google-glog (0.1-1) unstable; urgency=low
* Initial release.
-- Google Inc. <opensource@google.com> Sat, 10 May 2008 12:31:10 +0900

1
packages/deb/compat Normal file
View File

@ -0,0 +1 @@
4

23
packages/deb/control Normal file
View File

@ -0,0 +1,23 @@
Source: google-glog
Priority: optional
Maintainer: Google Inc. <opensource@google.com>
Build-Depends: debhelper (>= 4.0.0), binutils
Standards-Version: 3.6.1
Package: libgoogle-glog-dev
Section: libdevel
Architecture: any
Depends: libgoogle-glog0 (= ${Source-Version})
Description: a library that implements application-level logging.
This library provides logging APIs based on C++-style streams and
various helper macros. The devel package contains static and debug
libraries and header files for developing applications that use the
google-glog package.
Package: libgoogle-glog0
Section: libs
Architecture: any
Depends: ${shlibs:Depends}
Description: a library that implements application-level logging.
This library provides logging APIs based on C++-style streams and
various helper macros.

35
packages/deb/copyright Normal file
View File

@ -0,0 +1,35 @@
This package was debianized by Google Inc. <opensource@google.com> on
13 June 2008.
It was downloaded from http://code.google.com/
Upstream Author: opensource@google.com
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.

8
packages/deb/docs Normal file
View File

@ -0,0 +1,8 @@
AUTHORS
COPYING
ChangeLog
INSTALL
NEWS
README
doc/designstyle.css
doc/glog.html

View File

@ -0,0 +1,3 @@
usr/lib
usr/include
usr/include/glog

View File

@ -0,0 +1,8 @@
usr/include/glog/*
usr/lib/lib*.so
usr/lib/lib*.a
usr/lib/*.la
debian/tmp/usr/include/glog/*
debian/tmp/usr/lib/lib*.so
debian/tmp/usr/lib/lib*.a
debian/tmp/usr/lib/*.la

View File

@ -0,0 +1 @@
usr/lib

View File

@ -0,0 +1,2 @@
usr/lib/lib*.so.*
debian/tmp/usr/lib/lib*.so.*

117
packages/deb/rules Executable file
View File

@ -0,0 +1,117 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
CFLAGS = -Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
else
CFLAGS += -O2
endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
INSTALL_PROGRAM += -s
endif
# shared library versions, option 1
#version=2.0.5
#major=2
# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so
version=`ls src/.libs/lib*.so.* | \
awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'`
major=`ls src/.libs/lib*.so.* | \
awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'`
config.status: configure
dh_testdir
# Add here commands to configure the package.
CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
build: build-stamp
build-stamp: config.status
dh_testdir
# Add here commands to compile the package.
$(MAKE)
touch build-stamp
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
-$(MAKE) distclean
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
endif
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/tmp
$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs ChangeLog
dh_installdocs
dh_installexamples
dh_install --sourcedir=debian/tmp
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
# dh_python
dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

75
packages/rpm.sh Executable file
View File

@ -0,0 +1,75 @@
#!/bin/sh -e
# Run this from the 'packages' directory, just under rootdir
# We can only build rpm packages, if the rpm build tools are installed
if [ \! -x /usr/bin/rpmbuild ]
then
echo "Cannot find /usr/bin/rpmbuild. Not building an rpm." 1>&2
exit 0
fi
# Check the commandline flags
PACKAGE="$1"
VERSION="$2"
fullname="${PACKAGE}-${VERSION}"
archive=../$fullname.tar.gz
if [ -z "$1" -o -z "$2" ]
then
echo "Usage: $0 <package name> <package version>" 1>&2
exit 0
fi
# Double-check we're in the packages directory, just under rootdir
if [ \! -r ../Makefile -a \! -r ../INSTALL ]
then
echo "Must run $0 in the 'packages' directory, under the root directory." 1>&2
echo "Also, you must run \"make dist\" before running this script." 1>&2
exit 0
fi
if [ \! -r "$archive" ]
then
echo "Cannot find $archive. Run \"make dist\" first." 1>&2
exit 0
fi
# Create the directory where the input lives, and where the output should live
RPM_SOURCE_DIR="/tmp/rpmsource-$fullname"
RPM_BUILD_DIR="/tmp/rpmbuild-$fullname"
trap 'rm -rf $RPM_SOURCE_DIR $RPM_BUILD_DIR; exit $?' EXIT SIGHUP SIGINT SIGTERM
rm -rf "$RPM_SOURCE_DIR" "$RPM_BUILD_DIR"
mkdir "$RPM_SOURCE_DIR"
mkdir "$RPM_BUILD_DIR"
cp "$archive" "$RPM_SOURCE_DIR"
rpmbuild -bb rpm/rpm.spec \
--define "NAME $PACKAGE" \
--define "VERSION $VERSION" \
--define "_sourcedir $RPM_SOURCE_DIR" \
--define "_builddir $RPM_BUILD_DIR" \
--define "_rpmdir $RPM_SOURCE_DIR"
# We put the output in a directory based on what system we've built for
destdir=rpm-unknown
if [ -r /etc/issue ]
then
grep "Red Hat.*release 7" /etc/issue >/dev/null 2>&1 && destdir=rh7
grep "Red Hat.*release 8" /etc/issue >/dev/null 2>&1 && destdir=rh8
grep "Red Hat.*release 9" /etc/issue >/dev/null 2>&1 && destdir=rh9
if grep Fedora /etc/issue >/dev/null; then
destdir=fc`grep Fedora /etc/issue | cut -d' ' -f 4`;
fi
fi
rm -rf "$destdir"
mkdir -p "$destdir"
# We want to get not only the main package but devel etc, hence the middle *
mv "$RPM_SOURCE_DIR"/*/"${PACKAGE}"-*"${VERSION}"*.rpm "$destdir"
echo
echo "The rpm package file(s) are located in $PWD/$destdir"

71
packages/rpm/rpm.spec Normal file
View File

@ -0,0 +1,71 @@
%define RELEASE 1
%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
%define prefix /usr
Name: %NAME
Summary: A C++ application logging library
Version: %VERSION
Release: %rel
Group: Development/Libraries
URL: http://code.google.com/p/google-glog
License: BSD
Vendor: Google
Packager: Google Inc. <opensource@google.com>
Source: http://%{NAME}.googlecode.com/files/%{NAME}-%{VERSION}.tar.gz
Distribution: Redhat 7 and above.
Buildroot: %{_tmppath}/%{name}-root
Prefix: %prefix
%description
The %name package contains a library that implements application-level
logging. This library provides logging APIs based on C++-style
streams and various helper macros.
%package devel
Summary: A C++ application logging library
Group: Development/Libraries
Requires: %{NAME} = %{VERSION}
%description devel
The %name-devel package contains static and debug libraries and header
files for developing applications that use the %name package.
%changelog
* Wed Mar 26 2008 <opensource@google.com>
- First draft
%prep
%setup
%build
./configure
make prefix=%prefix
%install
rm -rf $RPM_BUILD_ROOT
make prefix=$RPM_BUILD_ROOT%{prefix} install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
## Mark all installed files within /usr/share/doc/{package name} as
## documentation. This depends on the following two lines appearing in
## Makefile.am:
## docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
## dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README
%docdir %{prefix}/share/doc/%{NAME}-%{VERSION}
%{prefix}/share/doc/%{NAME}-%{VERSION}/*
%{prefix}/lib/libglog.so.0
%{prefix}/lib/libglog.so.0.0.0
%files devel
%defattr(-,root,root)
%{prefix}/include/glog
%{prefix}/lib/libglog.a
%{prefix}/lib/libglog.la
%{prefix}/lib/libglog.so

117
src/base/commandlineflags.h Normal file
View File

@ -0,0 +1,117 @@
// 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.
// ---
// This file is a compatibility layer that defines Google's version of
// command line flags that are used for configuration.
//
// We put flags into their own namespace. It is purposefully
// named in an opaque way that people should have trouble typing
// directly. The idea is that DEFINE puts the flag in the weird
// namespace, and DECLARE imports the flag from there into the
// current namespace. The net result is to force people to use
// DECLARE to get access to a flag, rather than saying
// extern bool FLAGS_logtostderr;
// or some such instead. We want this so we can put extra
// functionality (like sanity-checking) in DECLARE if we want,
// and make sure it is picked up everywhere.
//
// We also put the type of the variable in the namespace, so that
// people can't DECLARE_int32 something that they DEFINE_bool'd
// elsewhere.
#ifndef BASE_COMMANDLINEFLAGS_H__
#define BASE_COMMANDLINEFLAGS_H__
#include "config.h"
#include <string>
#include <string.h> // for memchr
#include <stdlib.h> // for getenv
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
#else
#include "glog/logging.h"
#define DECLARE_VARIABLE(type, name, tn) \
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead { \
extern type FLAGS_##name; \
} \
using FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead::FLAGS_##name
#define DEFINE_VARIABLE(type, name, value, meaning, tn) \
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead { \
type FLAGS_##name(value); \
char FLAGS_no##name; \
} \
using FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead::FLAGS_##name
// bool specialization
#define DECLARE_bool(name) \
DECLARE_VARIABLE(bool, name, bool)
#define DEFINE_bool(name, value, meaning) \
DEFINE_VARIABLE(bool, name, EnvToBool("GLOG_" #name, value), meaning, bool)
// int32 specialization
#define DECLARE_int32(name) \
DECLARE_VARIABLE(@ac_google_namespace@::int32, name, int32)
#define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, name, \
EnvToInt("GLOG_" #name, value), meaning, int32)
// 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 FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \
extern std::string FLAGS_##name; \
} \
using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
#define DEFINE_string(name, value, meaning) \
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \
std::string FLAGS_##name(EnvToString("GLOG_" #name, value)); \
char FLAGS_no##name; \
} \
using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
// These macros (could be functions, but I don't want to bother with a .cc
// file), make it easier to initialize flags from the environment.
#define EnvToString(envname, dflt) \
(!getenv(envname) ? (dflt) : getenv(envname))
#define EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL)
#define EnvToInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10))
#endif // HAVE_LIB_GFLAGS
#endif // BASE_COMMANDLINEFLAGS_H__

51
src/base/googleinit.h Normal file
View File

@ -0,0 +1,51 @@
// 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.
// ---
// Author: Jacob Hoffman-Andrews
#ifndef _GOOGLEINIT_H
#define _GOOGLEINIT_H
class GoogleInitializer {
public:
typedef void (*void_function)(void);
GoogleInitializer(const char* name, void_function f) {
f();
}
};
#define REGISTER_MODULE_INITIALIZER(name, body) \
namespace { \
static void google_init_module_##name () { body; } \
GoogleInitializer google_initializer_module_##name(#name, \
google_init_module_##name); \
}
#endif /* _GOOGLEINIT_H */

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

@ -0,0 +1,252 @@
/* 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, so it's defined in the
* global namespace. If you want to expose it, you'll want to move
* it to the Google namespace.
*
* 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.
*/
// TODO(hamaji): Probably we must provide way to ensure static mutexes are
// initialized before they are used.
// (Google3's NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX)
#ifndef GOOGLE_MUTEX_H__
#define GOOGLE_MUTEX_H__
#include "config.h" // to figure out pthreads support
#include "utilities.h" // to get OS_* macro
#if defined(NO_THREADS)
typedef int MutexType; // to keep a lock-count
#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__
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
# endif
# include <pthread.h>
typedef pthread_rwlock_t MutexType;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
#elif defined(OS_WINDOWS)
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
# 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.
# define NOGDI
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
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_;
// Catch the error of writing Mutex when intending MutexLock.
Mutex(Mutex *ignored) {}
// Disallow "evil" constructors
Mutex(const Mutex&);
void operator=(const Mutex&);
};
// 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.
#include <assert.h>
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(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#include <stdlib.h> // for abort()
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return pthread_rwlock_trywrlock(&mutex_) == 0; }
#endif
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#include <stdlib.h> // for abort()
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
Mutex::Mutex() { SAFE_PTHREAD(pthread_mutex_init(&mutex_, NULL)); }
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy(&mutex_)); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock(&mutex_)); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&mutex_)); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return pthread_mutex_trylock(&mutex_) == 0; }
#endif
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
#elif defined(WIN32)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { LeaveCriticalSection(&mutex_); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return TryEnterCriticalSection(&mutex_) != 0; }
#endif
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#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&);
void operator=(const MutexLock&);
};
// 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&);
void operator=(const ReaderMutexLock&);
};
class WriterMutexLock {
public:
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
~WriterMutexLock() { mu_->WriterUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
WriterMutexLock(const WriterMutexLock&);
void operator=(const WriterMutexLock&);
};
// 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)
#endif /* #define GOOGLE_MUTEX_H__ */

104
src/config.h.in Normal file
View File

@ -0,0 +1,104 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Namespace for Google classes */
#undef GOOGLE_NAMESPACE
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* define if you have google gflags library */
#undef HAVE_LIB_GFLAGS
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* define if the compiler implements namespaces */
#undef HAVE_NAMESPACES
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* define if the compiler implements pthread_rwlock_* */
#undef HAVE_RWLOCK
/* Define if you have the `sigaltstack' function */
#undef HAVE_SIGALTSTACK
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <syscall.h> header file. */
#undef HAVE_SYSCALL_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/syscall.h> header file. */
#undef HAVE_SYS_SYSCALL_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* define if your compiler has __attribute__ */
#undef HAVE___ATTRIBUTE__
/* define if your compiler has __builtin_expect */
#undef HAVE___BUILTIN_EXPECT
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* The size of a `void *', as computed by sizeof. */
#undef SIZEOF_VOID_P
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* the namespace where STL code like vector<> is defined */
#undef STL_NAMESPACE
/* Version number of package */
#undef VERSION
/* Stops putting the code inside the Google namespace */
#undef _END_GOOGLE_NAMESPACE_
/* Puts following code inside the Google namespace */
#undef _START_GOOGLE_NAMESPACE_

1203
src/demangle.cc Normal file

File diff suppressed because it is too large Load Diff

56
src/demangle.h Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Satoru Takabayashi
//
// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
// (aka G++ V3 ABI).
// The demangler is implemented to be used in async signal handlers to
// symbolize stack traces. We cannot use libstdc++'s
// abi::__cxa_demangle() in such signal handlers since it's not async
// signal safe (it uses malloc() internally).
//
// Note that this demangler doesn't support full demangling. More
// specifically, it doesn't print types of function parameters and
// types of template arguments. It just skips them. However, it's
// still very useful to extract basic information such as class,
// function, constructor, destructor, and operator names.
//
// See the implementation note in demangle.cc if you are interested.
//
// Example:
//
// | Mangled Name | The Demangler | abi::__cxa_demangle()
// |---------------|---------------|-----------------------
// | _Z1fv | f() | f()
// | _Z1fi | f() | f(int)
// | _Z3foo3bar | foo() | foo(bar)
// | _Z1fIiEvi | f<>() | void f<int>(int)
// | _ZN1N1fE | N::f | N::f
// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
// | _Zrm1XS_" | operator%() | operator%(X, X)
// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
// | _Z1fSs | f() | f(std::basic_string<char,
// | | | std::char_traits<char>,
// | | | std::allocator<char> >)
//
// See the unit test for more examples.
//
// Note: we might want to write demanglers for ABIs other than Itanium
// C++ ABI in the future.
//
#ifndef BASE_DEMANGLE_H_
#define BASE_DEMANGLE_H_
#include "config.h"
_START_GOOGLE_NAMESPACE_
// Demangle "mangled". On success, return true and write the
// demangled symbol name to "out". Otherwise, return false.
// "out" is modified even if demangling is unsuccessful.
bool Demangle(const char *mangled, char *out, int out_size);
_END_GOOGLE_NAMESPACE_
#endif // BASE_DEMANGLE_H_

83
src/demangle_unittest.cc Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Satoru Takabayashi
//
// Unit tests for functions in demangle.c.
#include <iostream>
#include <fstream>
#include <string>
#include "glog/logging.h"
#include "demangle.h"
#include "googletest.h"
#include "config.h"
DEFINE_bool(demangle_filter, false, "Run demangle_unittest in filter mode");
using namespace std;
using namespace GOOGLE_NAMESPACE;
// A wrapper function for Demangle() to make the unit test simple.
static const char *DemangleIt(const char * const mangled) {
static char demangled[4096];
if (Demangle(mangled, demangled, sizeof(demangled))) {
return demangled;
} else {
return mangled;
}
}
// Test corner cases of bounary conditions.
TEST(Demangle, CornerCases) {
char tmp[10];
EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp)));
// sizeof("foobar()") == 9
EXPECT_STREQ("foobar()", tmp);
EXPECT_TRUE(Demangle("_Z6foobarv", tmp, 9));
EXPECT_STREQ("foobar()", tmp);
EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 8)); // Not enough.
EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 1));
EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 0));
EXPECT_FALSE(Demangle("_Z6foobarv", NULL, 0)); // Should not cause SEGV.
}
TEST(Demangle, FromFile) {
string test_file = FLAGS_test_srcdir + "/src/demangle_unittest.txt";
ifstream f(test_file.c_str()); // The file should exist.
EXPECT_FALSE(f.fail());
string line;
while (getline(f, line)) {
// Lines start with '#' are considered as comments.
if (line.empty() || line[0] == '#') {
continue;
}
// Each line should contain a mangled name and a demangled name
// separated by '\t'. Example: "_Z3foo\tfoo"
string::size_type tab_pos = line.find('\t');
EXPECT_NE(string::npos, tab_pos);
string mangled = line.substr(0, tab_pos);
string demangled = line.substr(tab_pos + 1);
EXPECT_EQ(demangled, DemangleIt(mangled.c_str()));
}
}
int main(int argc, char **argv) {
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
if (FLAGS_demangle_filter) {
// Read from cin and write to cout.
string line;
while (getline(cin, line, '\n')) {
cout << DemangleIt(line.c_str()) << endl;
}
return 0;
} else if (argc > 1) {
cout << DemangleIt(argv[1]) << endl;
return 0;
} else {
return RUN_ALL_TESTS();
}
}

63
src/demangle_unittest.sh Executable file
View File

@ -0,0 +1,63 @@
#! /bin/sh
# Copyright 2006 Google, Inc. All Rights Reserved.
# Author: Satoru Takabayashi
#
# Unit tests for demangle.c with a real binary.
set -e
die () {
echo $1
exit 1
}
BINDIR=".libs"
LIBGLOG="$BINDIR/libglog.so"
DEMANGLER="$BINDIR/demangle_unittest"
if test -e "$DEMANGLER"; then
# We need shared object.
export LD_LIBRARY_PATH=$BINDIR
export DYLD_LIBRARY_PATH=$BINDIR
else
# For windows
DEMANGLER="./demangle_unittest.exe"
if ! test -e "$DEMANGLER"; then
echo "We coundn't find demangle_unittest binary."
exit 1
fi
fi
# Extract C++ mangled symbols from libbase.so.
NM_OUTPUT="demangle.nm"
nm "$LIBGLOG" | perl -nle 'print $1 if /\s(_Z\S+$)/' > "$NM_OUTPUT"
# Check if mangled symbols exist. If there are none, we quit.
# The binary is more likely compiled with GCC 2.95 or something old.
if ! grep --quiet '^_Z' "$NM_OUTPUT"; then
echo "PASS"
exit 0
fi
# Demangle the symbols using our demangler.
DM_OUTPUT="demangle.dm"
GLOG_demangle_filter=1 "$DEMANGLER" --demangle_filter < "$NM_OUTPUT" > "$DM_OUTPUT"
# Calculate the numbers of lines.
NM_LINES=`wc -l "$NM_OUTPUT" | awk '{ print $1 }'`
DM_LINES=`wc -l "$DM_OUTPUT" | awk '{ print $1 }'`
# Compare the numbers of lines. They must be the same.
if test "$NM_LINES" != "$DM_LINES"; then
die "$NM_OUTPUT and $DM_OUTPUT don't have the same numbers of lines"
fi
# Check if mangled symbols exist. They must not exist.
if grep --quiet '^_Z' "$DM_OUTPUT"; then
die "Mangled symbols found in $DM_OUTPUT"
fi
# All C++ symbols are demangled successfully.
echo "PASS"
exit 0

137
src/demangle_unittest.txt Normal file
View File

@ -0,0 +1,137 @@
# Test caces for demangle_unittest. Each line consists of a
# tab-separated pair of mangled and demangled symbol names.
# Constructors and destructors.
_ZN3FooC1Ev Foo::Foo()
_ZN3FooD1Ev Foo::~Foo()
_ZNSoD0Ev std::ostream::~ostream()
# G++ extensions.
_ZTCN10LogMessage9LogStreamE0_So LogMessage::LogStream
_ZTv0_n12_N10LogMessage9LogStreamD0Ev LogMessage::LogStream::~LogStream()
_ZThn4_N7icu_3_410UnicodeSetD0Ev icu_3_4::UnicodeSet::~UnicodeSet()
# A bug in g++'s C++ ABI version 2 (-fabi-version=2).
_ZN7NSSInfoI5groupjjXadL_Z10getgrgid_rEELZ19nss_getgrgid_r_nameEEC1Ei NSSInfo<>::NSSInfo()
# C linkage symbol names. Should keep them untouched.
main main
Demangle Demangle
_ZERO _ZERO
# Cast operator.
_Zcviv operator int()
_ZN3foocviEv foo::operator int()
# Versioned symbols.
_Z3Foo@GLIBCXX_3.4 Foo@GLIBCXX_3.4
_Z3Foo@@GLIBCXX_3.4 Foo@@GLIBCXX_3.4
# Abbreviations.
_ZNSaE std::allocator
_ZNSbE std::basic_string
_ZNSdE std::iostream
_ZNSiE std::istream
_ZNSoE std::ostream
_ZNSsE std::string
# Substitutions. We just replace them with ?.
_ZN3fooS_E foo::?
_ZN3foo3barS0_E foo::bar::?
_ZNcvT_IiEEv operator ?<>()
# "<< <" case.
_ZlsI3fooE operator<< <>
# Random things we found interesting.
_ZN3FooISt6vectorISsSaISsEEEclEv Foo<>::operator()()
_ZTI9Callback1IiE Callback1<>
_ZN7icu_3_47UMemorynwEj icu_3_4::UMemory::operator new()
_ZNSt6vectorIbE9push_backE std::vector<>::push_back
_ZNSt6vectorIbSaIbEE9push_backEb std::vector<>::push_back()
_ZlsRSoRK15PRIVATE_Counter operator<<()
_ZSt6fill_nIPPN9__gnu_cxx15_Hashtable_nodeISt4pairIKPKcjEEEjS8_ET_SA_T0_RKT1_ std::fill_n<>()
_ZZ3FoovE3Bar Foo()::Bar
_ZGVZ7UpTimervE8up_timer UpTimer()::up_timer
# Test cases from gcc-4.1.0/libstdc++-v3/testsuite/demangle.
# Collected by:
# % grep verify_demangle **/*.cc | perl -nle 'print $1 if /"(_Z.*?)"/' |
# sort | uniq
#
# Note that the following symbols are invalid.
# That's why they are not demangled.
# - _ZNZN1N1fEiE1X1gE
# - _ZNZN1N1fEiE1X1gEv
# - _Z1xINiEE
_Z1fA37_iPS_ f()
_Z1fAszL_ZZNK1N1A1fEvE3foo_0E_i f()
_Z1fI1APS0_PKS0_EvT_T0_T1_PA4_S3_M1CS8_ f<>()
_Z1fI1XENT_1tES2_ f<>()
_Z1fI1XEvPVN1AIT_E1TE f<>()
_Z1fILi1ELc120EEv1AIXplT_cviLd4028ae147ae147aeEEE f<>()
_Z1fILi1ELc120EEv1AIXplT_cviLf3f800000EEE f<>()
_Z1fILi5E1AEvN1CIXqugtT_Li0ELi1ELi2EEE1qE f<>()
_Z1fILi5E1AEvN1CIXstN1T1tEEXszsrS2_1tEE1qE f<>()
_Z1fILi5EEvN1AIXcvimlT_Li22EEE1qE f<>()
_Z1fIiEvi f<>()
_Z1fKPFiiE f()
_Z1fM1AFivEPS0_ f()
_Z1fM1AKFivE f()
_Z1fM1AKFvvE f()
_Z1fPFPA1_ivE f()
_Z1fPFYPFiiEiE f()
_Z1fPFvvEM1SFvvE f()
_Z1fPKM1AFivE f()
_Z1fi f()
_Z1fv f()
_Z1jM1AFivEPS1_ j()
_Z1rM1GFivEMS_KFivES_M1HFivES1_4whatIKS_E5what2IS8_ES3_ r()
_Z1sPA37_iPS0_ s()
_Z1xINiEE _Z1xINiEE
_Z3absILi11EEvv abs<>()
_Z3foo3bar foo()
_Z3foo5Hello5WorldS0_S_ foo()
_Z3fooA30_A_i foo()
_Z3fooIA6_KiEvA9_KT_rVPrS4_ foo<>()
_Z3fooILi2EEvRAplT_Li1E_i foo<>()
_Z3fooIiFvdEiEvv foo<>()
_Z3fooPM2ABi foo()
_Z3fooc foo()
_Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_ foo()
_Z3kooPA28_A30_i koo()
_Z4makeI7FactoryiET_IT0_Ev make<>()
_Z5firstI3DuoEvS0_ first<>()
_Z5firstI3DuoEvT_ first<>()
_Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE hairyfunc()
_ZGVN5libcw24_GLOBAL__N_cbll.cc0ZhUKa23compiler_bug_workaroundISt6vectorINS_13omanip_id_tctINS_5debug32memblk_types_manipulator_data_ctEEESaIS6_EEE3idsE libcw::(anonymous namespace)::compiler_bug_workaround<>::ids
_ZN12libcw_app_ct10add_optionIS_EEvMT_FvPKcES3_cS3_S3_ libcw_app_ct::add_option<>()
_ZN1AIfEcvT_IiEEv A<>::operator ?<>()
_ZN1N1TIiiE2mfES0_IddE N::T<>::mf()
_ZN1N1fE N::f
_ZN1f1fE f::f
_ZN3FooIA4_iE3barE Foo<>::bar
_ZN5Arena5levelE Arena::level
_ZN5StackIiiE5levelE Stack<>::level
_ZN5libcw5debug13cwprint_usingINS_9_private_12GlobalObjectEEENS0_17cwprint_using_tctIT_EERKS5_MS5_KFvRSt7ostreamE libcw::debug::cwprint_using<>()
_ZN6System5Sound4beepEv System::Sound::beep()
_ZNKSt14priority_queueIP27timer_event_request_base_ctSt5dequeIS1_SaIS1_EE13timer_greaterE3topEv std::priority_queue<>::top()
_ZNKSt15_Deque_iteratorIP15memory_block_stRKS1_PS2_EeqERKS5_ std::_Deque_iterator<>::operator==()
_ZNKSt17__normal_iteratorIPK6optionSt6vectorIS0_SaIS0_EEEmiERKS6_ std::__normal_iterator<>::operator-()
_ZNSbIcSt11char_traitsIcEN5libcw5debug27no_alloc_checking_allocatorEE12_S_constructIPcEES6_T_S7_RKS3_ std::basic_string<>::_S_construct<>()
_ZNSt13_Alloc_traitsISbIcSt18string_char_traitsIcEN5libcw5debug9_private_17allocator_adaptorIcSt24__default_alloc_templateILb0ELi327664EELb1EEEENS5_IS9_S7_Lb1EEEE15_S_instancelessE std::_Alloc_traits<>::_S_instanceless
_ZNSt3_In4wardE std::_In::ward
_ZNZN1N1fEiE1X1gE _ZNZN1N1fEiE1X1gE
_ZNZN1N1fEiE1X1gEv _ZNZN1N1fEiE1X1gEv
_ZSt1BISt1DIP1ARKS2_PS3_ES0_IS2_RS2_PS2_ES2_ET0_T_SB_SA_PT1_ std::B<>()
_ZSt5state std::state
_ZTI7a_class a_class
_ZZN1N1fEiE1p N::f()::p
_ZZN1N1fEiEs N::f()
_ZlsRK1XS1_ operator<<()
_ZlsRKU3fooU4bart1XS0_ operator<<()
_ZlsRKU3fooU4bart1XS2_ operator<<()
_ZlsRSoRKSs operator<<()
_ZngILi42EEvN1AIXplT_Li2EEE1TE operator-<>()
_ZplR1XS0_ operator+()
_Zrm1XS_ operator%()

48
src/glog/log_severity.h Normal file
View File

@ -0,0 +1,48 @@
// Copyright 2007 Google Inc. All Rights Reserved.
#ifndef BASE_LOG_SEVERITY_H__
#define BASE_LOG_SEVERITY_H__
// Variables of type LogSeverity are widely taken to lie in the range
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
// you ever need to change their values or add a new severity.
typedef int LogSeverity;
const int INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3, NUM_SEVERITIES = 4;
// DFATAL is FATAL in debug mode, ERROR in normal mode
#ifdef NDEBUG
#define DFATAL_LEVEL ERROR
#else
#define DFATAL_LEVEL FATAL
#endif
extern const char* const LogSeverityNames[NUM_SEVERITIES];
// NDEBUG usage helpers related to (RAW_)DCHECK:
//
// DEBUG_MODE is for small !NDEBUG uses like
// if (DEBUG_MODE) foo.CheckThatFoo();
// instead of substantially more verbose
// #ifndef NDEBUG
// foo.CheckThatFoo();
// #endif
//
// IF_DEBUG_MODE is for small !NDEBUG uses like
// IF_DEBUG_MODE( string error; )
// DCHECK(Foo(&error)) << error;
// instead of substantially more verbose
// #ifndef NDEBUG
// string error;
// DCHECK(Foo(&error)) << error;
// #endif
//
#ifdef NDEBUG
enum { DEBUG_MODE = 0 };
#define IF_DEBUG_MODE(x)
#else
enum { DEBUG_MODE = 1 };
#define IF_DEBUG_MODE(x) x
#endif
#endif // BASE_LOG_SEVERITY_H__

1289
src/glog/logging.h.in Normal file

File diff suppressed because it is too large Load Diff

87
src/glog/raw_logging.h.in Normal file
View File

@ -0,0 +1,87 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Maxim Lifantsev
//
// Logging routines that do not allocate any memory and acquire any
// locks, and can therefore be used by low-level memory allocation
// and synchronization code.
#ifndef BASE_RAW_LOGGING_H__
#define BASE_RAW_LOGGING_H__
@ac_google_start_namespace@
#include "glog/log_severity.h"
#include "glog/vlog_is_on.h"
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
// but
// * it is to be used ONLY by low-level modules that can't use normal LOG()
// * it is desiged to be a low-level logger that does not allocate any
// memory and does not need any locks, hence:
// * it logs straight and ONLY to STDERR w/o buffering
// * it uses an explicit format and arguments list
// * it will silently chop off really long message strings
// Usage example:
// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// RAW_VLOG(3, "status is %i", status);
// These will print an almost standard log lines like this to stderr only:
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
// I0821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \
do { \
@ac_google_namespace@::RawLog__(@ac_google_namespace@::severity, __FILE__, __LINE__, __VA_ARGS__); \
} while (0)
#define RAW_VLOG(verboselevel, ...) \
do { \
if (VLOG_IS_ON(verboselevel)) { \
@ac_google_namespace@::RawLog__(@ac_google_namespace@::INFO, __FILE__, __LINE__, __VA_ARGS__); \
} \
} while (0)
// Similar to CHECK(condition) << message,
// 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:
// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed.
#define RAW_CHECK(condition, message) \
do { \
if (!(condition)) { \
RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \
} while (0)
// Debug versions of RAW_LOG and RAW_CHECK
#ifndef NDEBUG
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#else // NDEBUG
#define RAW_DLOG(severity, ...) \
while (false) \
RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) \
while (false) \
RAW_CHECK(condition, message)
#endif // NDEBUG
// Helper function to implement RAW_LOG and RAW_VLOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
// This does not allocate memory or acquire locks.
void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...)
@ac_cv___attribute___printf_4_5@;
// Hack to propagate time information into this module so that
// this module does not have to directly call localtime_r(),
// which could allocate memory.
extern "C" struct ::tm;
void RawLog__SetLastTime(const struct ::tm& t);
@ac_google_end_namespace@
#endif // BASE_RAW_LOGGING_H__

128
src/glog/stl_logging.h.in Normal file
View File

@ -0,0 +1,128 @@
// Copyright 2003 Google, Inc.
// All Rights Reserved.
//
// Stream output operators for STL containers; to be used for logging *only*.
// Inclusion of this file lets you do:
//
// list<string> x;
// LOG(INFO) << "data: " << x;
// vector<int> v1, v2;
// CHECK_EQ(v1, v2);
//
// Note that if you want to use these operators from the non-global namespace,
// you may get an error since they are not in namespace std (and they are not
// in namespace std since that would result in undefined behavior). You may
// need to write
//
// using ::operator<<;
//
// to fix these errors.
#ifndef UTIL_GTL_STL_LOGGING_INL_H_
#define UTIL_GTL_STL_LOGGING_INL_H_
#if !@ac_cv_cxx_using_operator@
# error We do not support stl_logging for this compiler
#endif
#include <deque>
#include <list>
#include <map>
#include <ostream>
#include <set>
#include <utility>
#include <vector>
#ifdef __GNUC__
# include <ext/hash_set>
# include <ext/hash_map>
# include <ext/slist>
#endif
template<class First, class Second>
inline std::ostream& operator<<(std::ostream& out,
const std::pair<First, Second>& p) {
out << '(' << p.first << ", " << p.second << ')';
return out;
}
@ac_google_start_namespace@
template<class Iter>
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
using ::operator<<;
// Output at most 100 elements -- appropriate if used for logging.
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
if (i > 0) out << ' ';
out << *begin;
}
if (begin != end) {
out << " ...";
}
}
@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; \
}
OUTPUT_TWO_ARG_CONTAINER(std::vector)
OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::list)
#ifdef __GNUC__
OUTPUT_TWO_ARG_CONTAINER(__gnu_cxx::slist)
#endif
#undef OUTPUT_TWO_ARG_CONTAINER
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_THREE_ARG_CONTAINER(std::set)
OUTPUT_THREE_ARG_CONTAINER(std::multiset)
#undef OUTPUT_THREE_ARG_CONTAINER
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_FOUR_ARG_CONTAINER(std::map)
OUTPUT_FOUR_ARG_CONTAINER(std::multimap)
#ifdef __GNUC__
OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_set)
OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_multiset)
#endif
#undef OUTPUT_FOUR_ARG_CONTAINER
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4, T5>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
#ifdef __GNUC__
OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_map)
OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_multimap)
#endif
#undef OUTPUT_FIVE_ARG_CONTAINER
#endif // UTIL_GTL_STL_LOGGING_INL_H_

89
src/glog/vlog_is_on.h.in Normal file
View File

@ -0,0 +1,89 @@
// Copyright 1999, 2007 Google Inc. All Rights Reserved.
// Author: Ray Sidney and many others
//
// Defines the VLOG_IS_ON macro that controls the variable-verbosity
// conditional logging.
//
// It's used by VLOG and VLOG_IF in logging.h
// and by RAW_VLOG in raw_logging.h to trigger the logging.
//
// It can also be used directly e.g. like this:
// if (VLOG_IS_ON(2)) {
// // do some logging preparation and logging
// // that can't be accomplished e.g. via just VLOG(2) << ...;
// }
//
// The truth value that VLOG_IS_ON(level) returns is determined by
// the three verbosity level flags:
// --v=<n> Gives the default maximal active V-logging level;
// 0 is the default.
// Normally positive values are used for V-logging levels.
// --vmodule=<str> Gives the per-module maximal V-logging levels to override
// the value given by --v.
// E.g. "my_module=2,foo*=3" would change the logging level
// for all code in source files "my_module.*" and "foo*.*"
// ("-inl" suffixes are also disregarded for this matching).
//
// SetVLOGLevel helper function is provided to do limited dynamic control over
// V-logging by overriding the per-module settings given via --vmodule flag.
//
// CAVEAT: --vmodule functionality is not available in non gcc compilers.
//
#ifndef BASE_VLOG_IS_ON_H_
#define BASE_VLOG_IS_ON_H_
#include "glog/log_severity.h"
#if defined(__GNUC__)
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
// (Normally) the first time every VLOG_IS_ON(n) site is hit,
// we determine what variable will dynamically control logging at this site:
// it's either FLAGS_v or an appropriate internal variable
// matching the current source file that represents results of
// parsing of --vmodule flag and/or SetVLOGLevel calls.
#define VLOG_IS_ON(verboselevel) \
({ static @ac_google_namespace@::int32* vlocal__ = &@ac_google_namespace@::kLogSiteUninitialized; \
@ac_google_namespace@::int32 verbose_level__ = (verboselevel); \
(*vlocal__ >= verbose_level__) && \
((vlocal__ != &@ac_google_namespace@::kLogSiteUninitialized) || \
(@ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \
__FILE__, verbose_level__))); })
#else
// GNU extensions not available, so we do not support --vmodule.
// Dynamic value of FLAGS_v always controls the logging level.
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#endif
// Set VLOG(_IS_ON) level for module_pattern to log_level.
// This lets us dynamically control what is normally set by the --vmodule flag.
// Returns the level that previously applied to module_pattern.
// NOTE: To change the log level for VLOG(_IS_ON) sites
// that have already executed after/during InitGoogleLogging,
// one needs to supply the exact --vmodule pattern that applied to them.
// (If no --vmodule pattern applied to them
// the value of FLAGS_v will continue to control them.)
extern int SetVLOGLevel(const char* module_pattern, int log_level);
// Various declarations needed for VLOG_IS_ON above: =========================
// Special value used to indicate that a VLOG_IS_ON site has not been
// initialized. We make this a large value, so the common-case check
// of "*vlocal__ >= verbose_level__" in VLOG_IS_ON definition
// passes in such cases and InitVLOG3__ is then triggered.
extern @ac_google_namespace@::int32 kLogSiteUninitialized;
// Helper routine which determines the logging info for a particalur VLOG site.
// site_flag is the address of the site-local pointer to the controlling
// verbosity level
// site_default is the default to use for *site_flag
// fname is the current source file name
// verbose_level is the argument to VLOG_IS_ON
// We will return the return value for VLOG_IS_ON
// and if possible set *site_flag appropriately.
extern bool InitVLOG3__(@ac_google_namespace@::int32** site_flag,
@ac_google_namespace@::int32* site_default,
const char* fname,
@ac_google_namespace@::int32 verbose_level);
#endif // BASE_VLOG_IS_ON_H_

483
src/googletest.h Normal file
View File

@ -0,0 +1,483 @@
#ifdef GOOGLETEST_H__
#error You must not include this file twice.
#endif
#define GOOGLETEST_H__
#include <ctype.h>
#include <setjmp.h>
#include <time.h>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "base/commandlineflags.h"
using std::map;
using std::string;
using std::vector;
DEFINE_string(test_tmpdir, "/tmp", "Dir we use for temp files");
DEFINE_string(test_srcdir, ".",
"Source-dir root, needed to find glog_unittest_flagfile");
DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
_START_GOOGLE_NAMESPACE_
extern void (*g_logging_fail_func)();
// The following is some bare-bones testing infrastructure
#define EXPECT_TRUE(cond) \
do { \
if (!(cond)) { \
fprintf(stderr, "Check failed: %s\n", #cond); \
exit(1); \
} \
} while (0)
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
#define EXPECT_OP(op, val1, val2) \
do { \
if (!((val1) op (val2))) { \
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
exit(1); \
} \
} while (0)
#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
#define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
#define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
#define EXPECT_NAN(arg) \
do { \
if (!isnan(arg)) { \
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
exit(1); \
} \
} while (0)
#define EXPECT_INF(arg) \
do { \
if (!isinf(arg)) { \
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
exit(1); \
} \
} while (0)
#define EXPECT_DOUBLE_EQ(val1, val2) \
do { \
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
exit(1); \
} \
} while (0)
#define EXPECT_STREQ(val1, val2) \
do { \
if (strcmp((val1), (val2)) != 0) { \
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
exit(1); \
} \
} while (0)
static bool g_called_abort;
static jmp_buf g_jmp_buf;
static void CalledAbort() {
g_called_abort = true;
longjmp(g_jmp_buf, 1);
}
#define ASSERT_DEATH(fn, msg) \
do { \
g_called_abort = false; \
/* in logging.cc */ \
void (*original_logging_fail_func)() = g_logging_fail_func; \
g_logging_fail_func = &CalledAbort; \
if (!setjmp(g_jmp_buf)) fn; \
/* set back to their default */ \
g_logging_fail_func = original_logging_fail_func; \
if (!g_called_abort) { \
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
exit(1); \
} \
} while (0)
#ifdef NDEBUG
#define ASSERT_DEBUG_DEATH(fn, msg)
#else
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
#endif // NDEBUG
vector<void (*)()> g_testlist; // the tests to run
#define TEST(a, b) \
struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \
static void Run() { FlagSaver fs; RunTest(); } \
static void RunTest(); \
}; \
static Test_##a##_##b g_test_##a##_##b; \
void Test_##a##_##b::RunTest()
static int RUN_ALL_TESTS() {
vector<void (*)()>::const_iterator it;
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
(*it)();
}
fprintf(stderr, "Passed %d tests\n\nPASS\n", (int)g_testlist.size());
return 0;
}
// Benchmark tools.
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
map<string, void (*)(int)> g_benchlist; // the benchmarks to run
class BenchmarkRegisterer {
public:
BenchmarkRegisterer(const char* name, void (*function)(int iters)) {
EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);
}
};
static void RunSpecifiedBenchmarks() {
int iter_cnt = FLAGS_benchmark_iters;
puts("Benchmark\tTime(ns)\tIterations");
for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin();
iter != g_benchlist.end();
++iter) {
clock_t start = clock();
iter->second(iter_cnt);
double elapsed_ns =
((double)clock() - start) / CLOCKS_PER_SEC * 1000*1000*1000;
printf("%s\t%8.2lf\t%10d\n",
iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt);
}
puts("");
}
// ----------------------------------------------------------------------
// Golden file functions
// ----------------------------------------------------------------------
class CapturedStream {
public:
CapturedStream(int fd, const string & filename) :
fd_(fd),
uncaptured_fd_(-1),
filename_(filename) {
Capture();
}
~CapturedStream() {
if (uncaptured_fd_ != -1) {
CHECK(close(uncaptured_fd_) != -1);
}
}
// Start redirecting output to a file
void Capture() {
// Keep original stream for later
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_ = dup(fd_);
CHECK(uncaptured_fd_ != -1);
// Open file to save stream to
int cap_fd = open(filename_.c_str(),
O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR);
CHECK(cap_fd != -1);
// Send stdout/stderr to this file
fflush(NULL);
CHECK(dup2(cap_fd, fd_) != -1);
CHECK(close(cap_fd) != -1);
}
// Remove output redirection
void StopCapture() {
// Restore original stream
if (uncaptured_fd_ != -1) {
fflush(NULL);
CHECK(dup2(uncaptured_fd_, fd_) != -1);
}
}
const string & filename() const { return filename_; }
private:
int fd_; // file descriptor being captured
int uncaptured_fd_; // where the stream was originally being sent to
string filename_; // file where stream is being saved
};
static CapturedStream * s_captured_streams[STDERR_FILENO+1];
// Redirect a file descriptor to a file.
// fd - Should be STDOUT_FILENO or STDERR_FILENO
// filename - File where output should be stored
static void CaptureTestOutput(int fd, const string & filename) {
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
CHECK(s_captured_streams[fd] == NULL);
s_captured_streams[fd] = new CapturedStream(fd, filename);
}
static void CaptureTestStderr() {
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
}
// Return the size (in bytes) of a file
static size_t GetFileSize(FILE * file) {
fseek(file, 0, SEEK_END);
return static_cast<size_t>(ftell(file));
}
// Read the entire content of a file as a string
static string ReadEntireFile(FILE * file) {
const size_t file_size = GetFileSize(file);
char * const buffer = new char[file_size];
size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far
fseek(file, 0, SEEK_SET);
// Keep reading the file until we cannot read further or the
// pre-determined file size is reached.
do {
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size);
const string content = string(buffer, buffer+bytes_read);
delete[] buffer;
return content;
}
// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
// fd is STDERR_FILENO) as a string
static string GetCapturedTestOutput(int fd) {
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
CapturedStream * const cap = s_captured_streams[fd];
CHECK(cap)
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
// Make sure everything is flushed.
cap->StopCapture();
// Read the captured file.
FILE * const file = fopen(cap->filename().c_str(), "r");
const string content = ReadEntireFile(file);
fclose(file);
delete cap;
s_captured_streams[fd] = NULL;
return content;
}
// Get the captured stderr of a test as a string.
static string GetCapturedTestStderr() {
return GetCapturedTestOutput(STDERR_FILENO);
}
// Check if the string is [IWEF](\d{4}|DATE)
static bool IsLoggingPrefix(const string& s) {
if (s.size() != 5) return false;
if (!strchr("IWEF", s[0])) return false;
for (int i = 1; i <= 4; ++i) {
if (!isdigit(s[i]) && s[i] != "DATE"[i-1]) return false;
}
return true;
}
// Convert log output into normalized form.
//
// Example:
// I0102 030405 logging_unittest.cc:345] RAW: vlog -1
// => IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
static string MungeLine(const string& line) {
std::istringstream iss(line);
string before, logcode_date, time, thread_lineinfo;
iss >> logcode_date;
while (!IsLoggingPrefix(logcode_date)) {
before += " " + logcode_date;
if (iss.eof()) {
// We cannot find the header of log output.
return before;
}
iss >> logcode_date;
}
if (!before.empty()) before += " ";
iss >> time;
CHECK_EQ(6, time.size());
iss >> thread_lineinfo;
CHECK(!thread_lineinfo.empty());
if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
// We found thread ID.
string tmp;
iss >> tmp;
CHECK(!tmp.empty());
CHECK_EQ(']', tmp[tmp.size() - 1]);
thread_lineinfo = "THREADID " + tmp;
}
size_t index = thread_lineinfo.find(':');
CHECK_NE(string::npos, index);
thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
string rest;
std::getline(iss, rest);
return (before + logcode_date[0] + "DATE TIME__ " + thread_lineinfo +
MungeLine(rest));
}
static void StringReplace(string* str,
const string& oldsub,
const string& newsub) {
size_t pos = str->find(oldsub);
if (pos != string::npos) {
str->replace(pos, oldsub.size(), newsub.c_str());
}
}
static string Munge(const string& filename) {
FILE* fp = fopen(filename.c_str(), "rb");
CHECK(fp != NULL) << filename << ": couldn't open";
char buf[4096];
string result;
while (fgets(buf, 4095, fp)) {
string line = MungeLine(buf);
char null_str[256];
sprintf(null_str, "%p", NULL);
StringReplace(&line, "__NULLP__", null_str);
char errmsg_buf[100];
posix_strerror_r(0, errmsg_buf, sizeof(errmsg_buf));
if (*errmsg_buf == '\0') {
// MacOSX 10.4 and FreeBSD return empty string for errno=0.
// In such case, the we need to remove an extra space.
StringReplace(&line, "__SUCCESS__ ", "");
} else {
StringReplace(&line, "__SUCCESS__", errmsg_buf);
}
StringReplace(&line, "__ENOENT__", strerror(ENOENT));
StringReplace(&line, "__EINTR__", strerror(EINTR));
StringReplace(&line, "__ENXIO__", strerror(ENXIO));
StringReplace(&line, "__ENOEXEC__", strerror(ENOEXEC));
result += line + "\n";
}
fclose(fp);
return result;
}
static void WriteToFile(const string& body, const string& file) {
FILE* fp = fopen(file.c_str(), "wb");
fwrite(body.data(), 1, body.size(), fp);
fclose(fp);
}
static bool MungeAndDiffTestStderr(const string& golden_filename) {
CapturedStream* cap = s_captured_streams[STDERR_FILENO];
CHECK(cap) << ": did you forget CaptureTestStderr()?";
cap->StopCapture();
// Run munge
const string captured = Munge(cap->filename());
const string golden = Munge(golden_filename);
if (captured != golden) {
fprintf(stderr,
"Test with golden file failed. We'll try to show the diff:\n");
string munged_golden = golden_filename + ".munged";
WriteToFile(golden, munged_golden);
string munged_captured = cap->filename() + ".munged";
WriteToFile(captured, munged_captured);
string diffcmd("diff -u " + munged_golden + " " + munged_captured);
if (system(diffcmd.c_str()) != 0) {
fprintf(stderr, "diff command was failed.\n");
}
unlink(munged_golden.c_str());
unlink(munged_captured.c_str());
return false;
}
LOG(INFO) << "Diff was successful";
return true;
}
// Save flags used from logging_unittest.cc.
#ifndef HAVE_LIB_GFLAGS
struct FlagSaver {
FlagSaver()
: v_(FLAGS_v),
stderrthreshold_(FLAGS_stderrthreshold),
logtostderr_(FLAGS_logtostderr),
alsologtostderr_(FLAGS_alsologtostderr) {}
~FlagSaver() {
FLAGS_v = v_;
FLAGS_stderrthreshold = stderrthreshold_;
FLAGS_logtostderr = logtostderr_;
FLAGS_alsologtostderr = alsologtostderr_;
}
int v_;
int stderrthreshold_;
bool logtostderr_;
bool alsologtostderr_;
};
#endif
// TODO(hamaji): Make it portable.
class Thread {
public:
void SetJoinable(bool joinable) {}
void Start() {
pthread_create(&th_, NULL, &Thread::InvokeThread, this);
}
void Join() {
pthread_join(th_, NULL);
}
protected:
virtual void Run() = 0;
private:
static void* InvokeThread(void* self) {
((Thread*)self)->Run();
return NULL;
}
pthread_t th_;
};
// TODO(hamaji): Make it portable.
static void SleepForMilliseconds(int t) {
usleep(t * 1000);
}
// Add hook for operator new to ensure there are no memory allocation.
void (*g_new_hook)() = NULL;
_END_GOOGLE_NAMESPACE_
void* operator new(size_t size) {
if (GOOGLE_NAMESPACE::g_new_hook) {
GOOGLE_NAMESPACE::g_new_hook();
}
return malloc(size);
}
void* operator new[](size_t size) {
return ::operator new(size);
}
void operator delete(void* p) {
free(p);
}
void operator delete[](void* p) {
::operator delete(p);
}

1592
src/logging.cc Normal file

File diff suppressed because it is too large Load Diff

45
src/logging_striplog_test.sh Executable file
View File

@ -0,0 +1,45 @@
#! /bin/sh
# Copyright 2007 Google, Inc.
# All Rights Reserved.
#
# Author: Sergey Ioffe
get_strings () {
if test -e ".libs/$1"; then
binary=".libs/$1"
elif test -e "$1.exe"; then
binary="$1.exe"
else
echo "We coundn't find $1 binary."
exit 1
fi
strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf "%s ", $2}'
}
# Die if "$1" != "$2", print $3 as death reason
check_eq () {
if [ "$1" != "$2" ]; then
echo "Check failed: '$1' == '$2' ${3:+ ($3)}"
exit 1
fi
}
die () {
echo $1
exit 1
}
# Check that the string literals are appropriately stripped. This will
# not be the case in debug mode.
check_eq "`get_strings logging_striptest0`" "COND ERROR FATAL INFO WARNING "
check_eq "`get_strings logging_striptest2`" "COND ERROR FATAL "
check_eq "`get_strings logging_striptest10`" ""
# Check that LOG(FATAL) aborts even for large STRIP_LOG
./logging_striptest2 2>/dev/null && die "Did not abort for STRIP_LOG=2"
./logging_striptest10 2>/dev/null && die "Did not abort for STRIP_LOG=10"
echo "PASS"

View File

@ -0,0 +1,7 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: Sergey Ioffe
#define GOOGLE_STRIP_LOG 10
// Include the actual test.
#include "logging_striptest_main.cc"

View File

@ -0,0 +1,7 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: Sergey Ioffe
#define GOOGLE_STRIP_LOG 2
// Include the actual test.
#include "logging_striptest_main.cc"

View File

@ -0,0 +1,40 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: Sergey Ioffe
// The common part of the striplog tests.
#include <stdio.h>
#include <string>
#include <iosfwd>
#include "glog/logging.h"
#include "base/commandlineflags.h"
#include "config.h"
DECLARE_bool(logtostderr);
using std::string;
using namespace GOOGLE_NAMESPACE;
int CheckNoReturn(bool b) {
string s;
if (b) {
LOG(FATAL) << "Fatal";
} else {
return 0;
}
}
struct A { };
std::ostream &operator<<(std::ostream &str, const A&) {return str;}
int main(int argc, char* argv[]) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
LOG(INFO) << "TESTMESSAGE INFO";
LOG(WARNING) << 2 << "something" << "TESTMESSAGE WARNING"
<< 1 << 'c' << A() << std::endl;
LOG(ERROR) << "TESTMESSAGE ERROR";
bool flag = true;
(flag ? LOG(INFO) : LOG(ERROR)) << "TESTMESSAGE COND";
LOG(FATAL) << "TESTMESSAGE FATAL";
}

923
src/logging_unittest.cc Normal file
View File

@ -0,0 +1,923 @@
//
// Copyright 2002 Google, Inc.
// All Rights Reserved.
//
// Author: Ray Sidney
#include "utilities.h"
#include <fcntl.h>
#include <glob.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iomanip>
#include <iostream>
#include <queue>
#include <sstream>
#include <string>
#include <vector>
#include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "googletest.h"
using namespace std;
using namespace GOOGLE_NAMESPACE;
static void TestLogging(bool check_counts);
static void TestRawLogging();
static void LogWithLevels(int v, int severity, bool err, bool alsoerr);
static void TestLoggingLevels();
static void TestLogString();
static void TestLogSink();
static void TestLogSinkWaitTillSent();
static void TestCHECK();
static void TestDCHECK();
static void TestSTREQ();
static void TestBasename();
static void TestSymlink();
static void TestExtension();
static void TestWrapper();
static void TestErrno();
static void TestTruncate();
static int x = -1;
static void BM_Check1(int n) {
while (n-- > 0) {
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
}
}
BENCHMARK(BM_Check1);
static void CheckFailure(int a, int b, const char* file, int line, const char* msg);
static void BM_Check3(int n) {
while (n-- > 0) {
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
}
}
BENCHMARK(BM_Check3);
static void BM_Check2(int n) {
if (n == 17) {
x = 5;
}
while (n-- > 0) {
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
}
}
BENCHMARK(BM_Check2);
static void CheckFailure(int a, int b, const char* file, int line, const char* msg) {
}
int main(int argc, char **argv) {
// Test some basics before InitGoogleLogging:
CaptureTestStderr();
LogWithLevels(FLAGS_v, FLAGS_stderrthreshold,
FLAGS_logtostderr, FLAGS_alsologtostderr);
LogWithLevels(0, 0, 0, 0); // simulate "before global c-tors"
const string early_stderr = GetCapturedTestStderr();
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
RunSpecifiedBenchmarks();
// so that death tests run before we use threads
CHECK_EQ(RUN_ALL_TESTS(), 0);
CaptureTestStderr();
// re-emit early_stderr
LogMessage("dummy", LogMessage::kNoLogPrefix, INFO).stream() << early_stderr;
TestLogging(true);
TestRawLogging();
TestLoggingLevels();
TestLogString();
TestLogSink();
TestLogSinkWaitTillSent();
TestCHECK();
TestDCHECK();
TestSTREQ();
// TODO: The golden test portion of this test is very flakey.
EXPECT_TRUE(
MungeAndDiffTestStderr(FLAGS_test_srcdir + "/src/logging_unittest.err"));
FLAGS_logtostderr = false;
TestBasename();
TestSymlink();
TestExtension();
TestWrapper();
TestErrno();
TestTruncate();
LOG(INFO) << "PASS";
return 0;
}
void TestLogging(bool check_counts) {
int64 base_num_infos = LogMessage::num_messages(INFO);
int64 base_num_warning = LogMessage::num_messages(WARNING);
int64 base_num_errors = LogMessage::num_messages(ERROR);
LOG(INFO) << string("foo ") << "bar " << 10 << ' ' << 3.4;
for ( int i = 0; i < 10; ++i ) {
int old_errno = errno;
errno = i;
PLOG_EVERY_N(ERROR, 2) << "Plog every 2, iteration " << COUNTER;
errno = old_errno;
LOG_EVERY_N(ERROR, 3) << "Log every 3, iteration " << COUNTER << endl;
LOG_EVERY_N(ERROR, 4) << "Log every 4, iteration " << COUNTER << endl;
LOG_IF_EVERY_N(WARNING, true, 5) << "Log if every 5, iteration " << COUNTER;
LOG_IF_EVERY_N(WARNING, false, 3)
<< "Log if every 3, iteration " << COUNTER;
LOG_IF_EVERY_N(INFO, true, 1) << "Log if every 1, iteration " << COUNTER;
LOG_IF_EVERY_N(ERROR, (i < 3), 2)
<< "Log if less than 3 every 2, iteration " << COUNTER;
}
LOG_IF(WARNING, true) << "log_if this";
LOG_IF(WARNING, false) << "don't log_if this";
char s[] = "array";
LOG(INFO) << s;
const char const_s[] = "const array";
LOG(INFO) << const_s;
int j = 1000;
LOG(ERROR) << string("foo") << ' '<< j << ' ' << setw(10) << j << " "
<< setw(1) << hex << j;
LogMessage("foo", LogMessage::kNoLogPrefix, INFO).stream() << "no prefix";
if (check_counts) {
CHECK_EQ(base_num_infos + 14, LogMessage::num_messages(INFO));
CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(WARNING));
CHECK_EQ(base_num_errors + 15, LogMessage::num_messages(ERROR));
}
}
static void NoAllocNewHook() {
CHECK(false) << "unexpected new";
}
struct NewHook {
NewHook() {
g_new_hook = &NoAllocNewHook;
}
~NewHook() {
g_new_hook = NULL;
}
};
TEST(DeathNoAllocNewHook, logging) {
// tests that NewHook used below works
NewHook new_hook;
ASSERT_DEATH({
new int;
}, "unexpected new");
}
void TestRawLogging() {
string* foo = new string("foo ");
string huge_str(50000, 'a');
FlagSaver saver;
// Check that RAW loggging does not use mallocs.
NewHook new_hook;
RAW_LOG(INFO, "%s%s%d%c%f", foo->c_str(), "bar ", 10, ' ', 3.4);
char s[] = "array";
RAW_LOG(WARNING, "%s", s);
const char const_s[] = "const array";
RAW_LOG(INFO, "%s", const_s);
void* p = reinterpret_cast<void*>(0x12345678);
RAW_LOG(INFO, "ptr %p", p);
p = NULL;
RAW_LOG(INFO, "ptr %p", p);
int j = 1000;
RAW_LOG(ERROR, "%s%d%c%010d%s%1x", foo->c_str(), j, ' ', j, " ", j);
RAW_VLOG(0, "foo %d", j);
#ifdef NDEBUG
RAW_LOG(INFO, "foo %d", j); // so that have same stderr to compare
#else
RAW_DLOG(INFO, "foo %d", j); // test RAW_DLOG in debug mode
#endif
// test how long messages are chopped:
RAW_LOG(WARNING, "Huge string: %s", huge_str.c_str());
RAW_VLOG(0, "Huge string: %s", huge_str.c_str());
FLAGS_v = 0;
RAW_LOG(INFO, "log");
RAW_VLOG(0, "vlog 0 on");
RAW_VLOG(1, "vlog 1 off");
RAW_VLOG(2, "vlog 2 off");
RAW_VLOG(3, "vlog 3 off");
FLAGS_v = 2;
RAW_LOG(INFO, "log");
RAW_VLOG(1, "vlog 1 on");
RAW_VLOG(2, "vlog 2 on");
RAW_VLOG(3, "vlog 3 off");
#ifdef NDEBUG
RAW_DCHECK(1 == 2, " RAW_DCHECK's shouldn't be compiled in normal mode");
#endif
RAW_CHECK(1 == 1, "should be ok");
RAW_DCHECK(true, "should be ok");
delete foo;
}
void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
RAW_LOG(INFO,
"Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d",
v, severity, err, alsoerr);
FlagSaver saver;
FLAGS_v = v;
FLAGS_stderrthreshold = severity;
FLAGS_logtostderr = err;
FLAGS_alsologtostderr = alsoerr;
RAW_VLOG(-1, "vlog -1");
RAW_VLOG(0, "vlog 0");
RAW_VLOG(1, "vlog 1");
RAW_LOG(INFO, "log info");
RAW_LOG(WARNING, "log warning");
RAW_LOG(ERROR, "log error");
VLOG(-1) << "vlog -1";
VLOG(0) << "vlog 0";
VLOG(1) << "vlog 1";
LOG(INFO) << "log info";
LOG(WARNING) << "log warning";
LOG(ERROR) << "log error";
VLOG_IF(-1, true) << "vlog_if -1";
VLOG_IF(-1, false) << "don't vlog_if -1";
VLOG_IF(0, true) << "vlog_if 0";
VLOG_IF(0, false) << "don't vlog_if 0";
VLOG_IF(1, true) << "vlog_if 1";
VLOG_IF(1, false) << "don't vlog_if 1";
LOG_IF(INFO, true) << "log_if info";
LOG_IF(INFO, false) << "don't log_if info";
LOG_IF(WARNING, true) << "log_if warning";
LOG_IF(WARNING, false) << "don't log_if warning";
LOG_IF(ERROR, true) << "log_if error";
LOG_IF(ERROR, false) << "don't log_if error";
int c;
c = 1; VLOG_IF(100, c -= 2) << "vlog_if 100 expr"; EXPECT_EQ(c, -1);
c = 1; VLOG_IF(0, c -= 2) << "vlog_if 0 expr"; EXPECT_EQ(c, -1);
c = 1; LOG_IF(INFO, c -= 2) << "log_if info expr"; EXPECT_EQ(c, -1);
c = 1; LOG_IF(ERROR, c -= 2) << "log_if error expr"; EXPECT_EQ(c, -1);
c = 2; VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr"; EXPECT_EQ(c, 0);
c = 2; LOG_IF(ERROR, c -= 2) << "don't log_if error expr"; EXPECT_EQ(c, 0);
c = 3; LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr";
EXPECT_EQ(c, -1);
c = 3; LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr";
EXPECT_EQ(c, -1);
c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr";
EXPECT_EQ(c, 0);
c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr";
EXPECT_EQ(c, 0);
c = 5; VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr";
EXPECT_EQ(c, 1);
c = 5; VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr";
EXPECT_EQ(c, 1);
c = 6; VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr";
EXPECT_EQ(c, 0);
c = 6; VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr";
EXPECT_EQ(c, 0);
}
void TestLoggingLevels() {
LogWithLevels(0, INFO, false, false);
LogWithLevels(1, INFO, false, false);
LogWithLevels(-1, INFO, false, false);
LogWithLevels(0, WARNING, false, false);
LogWithLevels(0, ERROR, false, false);
LogWithLevels(0, FATAL, false, false);
LogWithLevels(0, FATAL, true, false);
LogWithLevels(0, FATAL, false, true);
LogWithLevels(1, WARNING, false, false);
LogWithLevels(1, FATAL, false, true);
}
TEST(DeathRawCHECK, logging) {
ASSERT_DEATH(RAW_CHECK(false, "failure 1"),
"RAW: Check false failed: failure 1");
ASSERT_DEBUG_DEATH(RAW_DCHECK(1 == 2, "failure 2"),
"RAW: Check 1 == 2 failed: failure 2");
}
void TestLogString() {
vector<string> errors;
vector<string> *no_errors = NULL;
LOG_STRING(INFO, &errors) << "LOG_STRING: " << "collected info";
LOG_STRING(WARNING, &errors) << "LOG_STRING: " << "collected warning";
LOG_STRING(ERROR, &errors) << "LOG_STRING: " << "collected error";
LOG_STRING(INFO, no_errors) << "LOG_STRING: " << "reported info";
LOG_STRING(WARNING, no_errors) << "LOG_STRING: " << "reported warning";
LOG_STRING(ERROR, NULL) << "LOG_STRING: " << "reported error";
for (int i = 0; i < errors.size(); ++i) {
LOG(INFO) << "Captured by LOG_STRING: " << errors[i];
}
}
class TestLogSinkImpl : public LogSink {
public:
vector<string> errors;
virtual void send(LogSeverity severity, const char* full_filename,
const char* base_filename, int line,
const struct tm* tm_time,
const char* message, size_t message_len) {
errors.push_back(
ToString(severity, base_filename, line, tm_time, message, message_len));
}
};
void TestLogSink() {
TestLogSinkImpl sink;
LogSink *no_sink = NULL;
LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: " << "collected info";
LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: " << "collected warning";
LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: " << "collected error";
LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: " << "reported info";
LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: " << "reported warning";
LOG_TO_SINK(NULL, ERROR) << "LOG_TO_SINK: " << "reported error";
LOG(INFO) << "Captured by LOG_TO_SINK:";
for (int i = 0; i < sink.errors.size(); ++i) {
LogMessage("foo", LogMessage::kNoLogPrefix, INFO).stream()
<< sink.errors[i];
}
}
// For testing using CHECK*() on anonymous enums.
enum {
CASE_A,
CASE_B
};
void TestCHECK() {
// Tests using CHECK*() on int values.
CHECK(1 == 1);
CHECK_EQ(1, 1);
CHECK_NE(1, 2);
CHECK_GE(1, 1);
CHECK_GE(2, 1);
CHECK_LE(1, 1);
CHECK_LE(1, 2);
CHECK_GT(2, 1);
CHECK_LT(1, 2);
// Tests using CHECK*() on anonymous enums.
// Apple's GCC doesn't like this.
#if !defined(OS_MACOSX)
CHECK_EQ(CASE_A, CASE_A);
CHECK_NE(CASE_A, CASE_B);
CHECK_GE(CASE_A, CASE_A);
CHECK_GE(CASE_B, CASE_A);
CHECK_LE(CASE_A, CASE_A);
CHECK_LE(CASE_A, CASE_B);
CHECK_GT(CASE_B, CASE_A);
CHECK_LT(CASE_A, CASE_B);
#endif
}
void TestDCHECK() {
#ifdef NDEBUG
DCHECK( 1 == 2 ) << " DCHECK's shouldn't be compiled in normal mode";
#endif
DCHECK( 1 == 1 );
DCHECK_EQ(1, 1);
DCHECK_NE(1, 2);
DCHECK_GE(1, 1);
DCHECK_GE(2, 1);
DCHECK_LE(1, 1);
DCHECK_LE(1, 2);
DCHECK_GT(2, 1);
DCHECK_LT(1, 2);
}
void TestSTREQ() {
CHECK_STREQ("this", "this");
CHECK_STREQ(NULL, NULL);
CHECK_STRCASEEQ("this", "tHiS");
CHECK_STRCASEEQ(NULL, NULL);
CHECK_STRNE("this", "tHiS");
CHECK_STRNE("this", NULL);
CHECK_STRCASENE("this", "that");
CHECK_STRCASENE(NULL, "that");
CHECK_STREQ((string("a")+"b").c_str(), "ab");
CHECK_STREQ(string("test").c_str(),
(string("te") + string("st")).c_str());
}
TEST(DeathSTREQ, logging) {
ASSERT_DEATH(CHECK_STREQ(NULL, "this"), "");
ASSERT_DEATH(CHECK_STREQ("this", "siht"), "");
ASSERT_DEATH(CHECK_STRCASEEQ(NULL, "siht"), "");
ASSERT_DEATH(CHECK_STRCASEEQ("this", "siht"), "");
ASSERT_DEATH(CHECK_STRNE(NULL, NULL), "");
ASSERT_DEATH(CHECK_STRNE("this", "this"), "");
ASSERT_DEATH(CHECK_STREQ((string("a")+"b").c_str(), "abc"), "");
}
TEST(CheckNOTNULL, Simple) {
int64 t;
void *ptr = static_cast<void *>(&t);
void *ref = CHECK_NOTNULL(ptr);
EXPECT_EQ(ptr, ref);
CHECK_NOTNULL(reinterpret_cast<char *>(&t));
CHECK_NOTNULL(reinterpret_cast<unsigned char *>(&t));
CHECK_NOTNULL(reinterpret_cast<int *>(&t));
CHECK_NOTNULL(reinterpret_cast<int64 *>(&t));
}
TEST(DeathCheckNN, Simple) {
ASSERT_DEATH(CHECK_NOTNULL(static_cast<void *>(NULL)), "");
}
// Get list of file names that match pattern
static void GetFiles(const string& pattern, vector<string>* files) {
files->clear();
glob_t g;
const int r = glob(pattern.c_str(), 0, NULL, &g);
CHECK((r == 0) || (r == GLOB_NOMATCH)) << ": error matching " << pattern;
for (int i = 0; i < g.gl_pathc; i++) {
files->push_back(string(g.gl_pathv[i]));
}
globfree(&g);
}
// Delete files patching pattern
static void DeleteFiles(const string& pattern) {
vector<string> files;
GetFiles(pattern, &files);
for (int i = 0; i < files.size(); i++) {
CHECK(unlink(files[i].c_str()) == 0) << ": " << strerror(errno);
}
}
static void CheckFile(const string& name, const string& expected_string) {
vector<string> files;
GetFiles(name + "*", &files);
CHECK_EQ(files.size(), 1);
FILE* file = fopen(files[0].c_str(), "r");
CHECK(file != NULL) << ": could not open " << files[0];
char buf[1000];
while (fgets(buf, sizeof(buf), file) != NULL) {
if (strstr(buf, expected_string.c_str()) != NULL) {
fclose(file);
return;
}
}
fclose(file);
LOG(FATAL) << "Did not find " << expected_string << " in " << files[0];
}
static void TestBasename() {
fprintf(stderr, "==== Test setting log file basename\n");
string dest = FLAGS_test_tmpdir + "/logging_test_basename";
DeleteFiles(dest + "*");
SetLogDestination(INFO, dest.c_str());
LOG(INFO) << "message to new base";
FlushLogFiles(INFO);
CheckFile(dest, "message to new base");
DeleteFiles(dest + "*");
}
static void TestSymlink() {
fprintf(stderr, "==== Test setting log file symlink\n");
string dest = FLAGS_test_tmpdir + "/logging_test_symlink";
string sym = FLAGS_test_tmpdir + "/symlinkbase";
DeleteFiles(dest + "*");
DeleteFiles(sym + "*");
SetLogSymlink(INFO, "symlinkbase");
SetLogDestination(INFO, dest.c_str());
LOG(INFO) << "message to new symlink";
FlushLogFiles(INFO);
CheckFile(sym, "message to new symlink");
DeleteFiles(dest + "*");
DeleteFiles(sym + "*");
}
static void TestExtension() {
fprintf(stderr, "==== Test setting log file extension\n");
string dest = FLAGS_test_tmpdir + "/logging_test_extension";
DeleteFiles(dest + "*");
SetLogDestination(INFO, dest.c_str());
SetLogFilenameExtension("specialextension");
LOG(INFO) << "message to new extension";
FlushLogFiles(INFO);
CheckFile(dest, "message to new extension");
// Check that file name ends with extension
vector<string> filenames;
GetFiles(dest + "*", &filenames);
CHECK_EQ(filenames.size(), 1);
CHECK(strstr(filenames[0].c_str(), "specialextension") != NULL);
DeleteFiles(dest + "*");
}
struct MyLogger : public base::Logger {
string data;
virtual void Write(bool should_flush,
time_t timestamp,
const char* message,
int length) {
data.append(message, length);
}
virtual void Flush() { }
virtual uint32 LogSize() { return data.length(); }
};
static void TestWrapper() {
fprintf(stderr, "==== Test log wrapper\n");
MyLogger my_logger;
base::Logger* old_logger = base::GetLogger(INFO);
base::SetLogger(INFO, &my_logger);
LOG(INFO) << "Send to wrapped logger";
FlushLogFiles(INFO);
base::SetLogger(INFO, old_logger);
CHECK(strstr(my_logger.data.c_str(), "Send to wrapped logger") != NULL);
}
static void TestErrno() {
fprintf(stderr, "==== Test errno preservation\n");
errno = ENOENT;
TestLogging(false);
CHECK_EQ(errno, ENOENT);
}
static void TestOneTruncate(const char *path, int64 limit, int64 keep,
int64 dsize, int64 ksize, int64 expect) {
int fd;
CHECK_ERR(fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600));
const char *discardstr = "DISCARDME!", *keepstr = "KEEPME!";
// Fill the file with the requested data; first discard data, then kept data
int64 written = 0;
while (written < dsize) {
int bytes = min<int64>(dsize - written, strlen(discardstr));
CHECK_ERR(write(fd, discardstr, bytes));
written += bytes;
}
written = 0;
while (written < ksize) {
int bytes = min<int64>(ksize - written, strlen(keepstr));
CHECK_ERR(write(fd, keepstr, bytes));
written += bytes;
}
TruncateLogFile(path, limit, keep);
// File should now be shorter
struct stat statbuf;
CHECK_ERR(fstat(fd, &statbuf));
CHECK_EQ(statbuf.st_size, expect);
CHECK_ERR(lseek(fd, 0, SEEK_SET));
// File should contain the suffix of the original file
char buf[statbuf.st_size + 1];
memset(buf, 0, sizeof(buf));
CHECK_ERR(read(fd, buf, sizeof(buf)));
const char *p = buf;
int64 checked = 0;
while (checked < expect) {
int bytes = min<int64>(expect - checked, strlen(keepstr));
CHECK(!memcmp(p, keepstr, bytes));
checked += bytes;
}
close(fd);
}
static void TestTruncate() {
fprintf(stderr, "==== Test log truncation\n");
string path = FLAGS_test_tmpdir + "/truncatefile";
// Test on a small file
TestOneTruncate(path.c_str(), 10, 10, 10, 10, 10);
// And a big file (multiple blocks to copy)
TestOneTruncate(path.c_str(), 2<<20, 4<<10, 3<<20, 4<<10, 4<<10);
// Check edge-case limits
TestOneTruncate(path.c_str(), 10, 20, 0, 20, 20);
TestOneTruncate(path.c_str(), 10, 0, 0, 0, 0);
TestOneTruncate(path.c_str(), 10, 50, 0, 10, 10);
TestOneTruncate(path.c_str(), 50, 100, 0, 30, 30);
// MacOSX 10.4 doesn't fail in this case. Let's just ignore this test.
#if !defined(OS_MACOSX)
// Through a symlink should fail to truncate
string linkname = path + ".link";
unlink(linkname.c_str());
CHECK_ERR(symlink(path.c_str(), linkname.c_str()));
TestOneTruncate(linkname.c_str(), 10, 10, 0, 30, 30);
#endif
// The /proc/self path makes sense only for linux.
#if defined(OS_LINUX)
// Through an open fd symlink should work
int fd;
CHECK_ERR(fd = open(path.c_str(), O_APPEND | O_WRONLY));
char fdpath[64];
snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd);
TestOneTruncate(fdpath, 10, 10, 10, 10, 10);
#endif
}
_START_GOOGLE_NAMESPACE_
extern // in logging.cc
bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len);
_END_GOOGLE_NAMESPACE_
static bool WrapSafeFNMatch(string pattern, string str) {
pattern += "abc";
str += "defgh";
return SafeFNMatch_(pattern.data(), pattern.size() - 3,
str.data(), str.size() - 5);
}
TEST(SafeFNMatch, logging) {
CHECK(WrapSafeFNMatch("foo", "foo"));
CHECK(!WrapSafeFNMatch("foo", "bar"));
CHECK(!WrapSafeFNMatch("foo", "fo"));
CHECK(!WrapSafeFNMatch("foo", "foo2"));
CHECK(WrapSafeFNMatch("bar/foo.ext", "bar/foo.ext"));
CHECK(WrapSafeFNMatch("*ba*r/fo*o.ext*", "bar/foo.ext"));
CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/baz.ext"));
CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/foo"));
CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/foo.ext.zip"));
CHECK(WrapSafeFNMatch("ba?/*.ext", "bar/foo.ext"));
CHECK(WrapSafeFNMatch("ba?/*.ext", "baZ/FOO.ext"));
CHECK(!WrapSafeFNMatch("ba?/*.ext", "barr/foo.ext"));
CHECK(!WrapSafeFNMatch("ba?/*.ext", "bar/foo.ext2"));
CHECK(WrapSafeFNMatch("ba?/*", "bar/foo.ext2"));
CHECK(WrapSafeFNMatch("ba?/*", "bar/"));
CHECK(!WrapSafeFNMatch("ba?/?", "bar/"));
CHECK(!WrapSafeFNMatch("ba?/*", "bar"));
}
// TestWaitingLogSink will save messages here
// No lock: Accessed only by TestLogSinkWriter thread
// and after its demise by its creator.
static vector<string> global_messages;
// helper for TestWaitingLogSink below.
// Thread that does the logic of TestWaitingLogSink
// It's free to use LOG() itself.
class TestLogSinkWriter : public Thread {
public:
TestLogSinkWriter() : should_exit_(false) {
SetJoinable(true);
Start();
}
// Just buffer it (can't use LOG() here).
void Buffer(const string& message) {
mutex_.Lock();
RAW_LOG(INFO, "Buffering");
messages_.push(message);
mutex_.Unlock();
RAW_LOG(INFO, "Buffered");
}
// Wait for the buffer to clear (can't use LOG() here).
void Wait() {
RAW_LOG(INFO, "Waiting");
mutex_.Lock();
while (!NoWork()) {
mutex_.Unlock();
SleepForMilliseconds(1);
mutex_.Lock();
}
RAW_LOG(INFO, "Waited");
mutex_.Unlock();
}
// Trigger thread exit.
void Stop() {
MutexLock l(&mutex_);
should_exit_ = true;
}
private:
// helpers ---------------
// For creating a "Condition".
bool NoWork() { return messages_.empty(); }
bool HaveWork() { return !messages_.empty() || should_exit_; }
// Thread body; CAN use LOG() here!
virtual void Run() {
while (1) {
mutex_.Lock();
while (!HaveWork()) {
mutex_.Unlock();
SleepForMilliseconds(1);
mutex_.Lock();
}
if (should_exit_ && messages_.empty()) {
mutex_.Unlock();
break;
}
// Give the main thread time to log its message,
// so that we get a reliable log capture to compare to golden file.
// Same for the other sleep below.
SleepForMilliseconds(20);
RAW_LOG(INFO, "Sink got a messages"); // only RAW_LOG under mutex_ here
string message = messages_.front();
messages_.pop();
// Normally this would be some more real/involved logging logic
// where LOG() usage can't be eliminated,
// e.g. pushing the message over with an RPC:
int messages_left = messages_.size();
mutex_.Unlock();
SleepForMilliseconds(20);
// May not use LOG while holding mutex_, because Buffer()
// acquires mutex_, and Buffer is called from LOG(),
// which has its own internal mutex:
// LOG()->LogToSinks()->TestWaitingLogSink::send()->Buffer()
LOG(INFO) << "Sink is sending out a message: " << message;
LOG(INFO) << "Have " << messages_left << " left";
global_messages.push_back(message);
}
}
// data ---------------
Mutex mutex_;
bool should_exit_;
queue<string> messages_; // messages to be logged
};
// A log sink that exercises WaitTillSent:
// it pushes data to a buffer and wakes up another thread to do the logging
// (that other thread can than use LOG() itself),
class TestWaitingLogSink : public LogSink {
public:
TestWaitingLogSink() {
tid_ = pthread_self(); // for thread-specific behavior
AddLogSink(this);
}
~TestWaitingLogSink() {
RemoveLogSink(this);
writer_.Stop();
writer_.Join();
}
// (re)define LogSink interface
virtual void send(LogSeverity severity, const char* full_filename,
const char* base_filename, int line,
const struct tm* tm_time,
const char* message, size_t message_len) {
// Push it to Writer thread if we are the original logging thread.
// Note: Something like ThreadLocalLogSink is a better choice
// to do thread-specific LogSink logic for real.
if (pthread_equal(tid_, pthread_self())) {
writer_.Buffer(ToString(severity, base_filename, line,
tm_time, message, message_len));
}
}
virtual void WaitTillSent() {
// Wait for Writer thread if we are the original logging thread.
if (pthread_equal(tid_, pthread_self())) writer_.Wait();
}
private:
pthread_t tid_;
TestLogSinkWriter writer_;
};
// Check that LogSink::WaitTillSent can be used in the advertised way.
// We also do golden-stderr comparison.
static void TestLogSinkWaitTillSent() {
{ TestWaitingLogSink sink;
// Sleeps give the sink threads time to do all their work,
// so that we get a reliable log capture to compare to the golden file.
LOG(INFO) << "Message 1";
SleepForMilliseconds(60);
LOG(ERROR) << "Message 2";
SleepForMilliseconds(60);
LOG(WARNING) << "Message 3";
SleepForMilliseconds(60);
}
for (int i = 0; i < global_messages.size(); ++i) {
LOG(INFO) << "Sink capture: " << global_messages[i];
}
CHECK_EQ(global_messages.size(), 3);
}
TEST(Strerror, logging) {
int errcode = EINTR;
char *msg = strdup(strerror(errcode));
char buf[strlen(msg) + 1];
CHECK_EQ(posix_strerror_r(errcode, NULL, 0), -1);
buf[0] = 'A';
CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
CHECK_EQ(buf[0], 'A');
CHECK_EQ(posix_strerror_r(errcode, NULL, sizeof(buf)), -1);
#if defined(OS_MACOSX) || defined(OS_FREEBSD)
// MacOSX or FreeBSD considers this case is an error since there is
// no enough space.
CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
#else
CHECK_EQ(posix_strerror_r(errcode, buf, 1), 0);
#endif
CHECK_STREQ(buf, "");
CHECK_EQ(posix_strerror_r(errcode, buf, sizeof(buf)), 0);
CHECK_STREQ(buf, msg);
free(msg);
}
// Simple routines to look at the sizes of generated code for LOG(FATAL) and
// CHECK(..) via objdump
void MyFatal() {
LOG(FATAL) << "Failed";
}
void MyCheck(bool a, bool b) {
CHECK_EQ(a, b);
}
struct UserDefinedClass {
bool operator==(const UserDefinedClass& rhs) const { return true; }
};
inline ostream& operator<<(ostream& out, const UserDefinedClass& u) {
out << "OK";
return out;
}
TEST(UserDefinedClass, logging) {
UserDefinedClass u;
vector<string> buf;
LOG_STRING(INFO, &buf) << u;
CHECK_EQ(1, buf.size());
CHECK(buf[0].find("OK") != string::npos);
// We must be able to compile this.
CHECK_EQ(u, u);
}

293
src/logging_unittest.err Normal file
View File

@ -0,0 +1,293 @@
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=2 logtostderr=0 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
WARNING: Logging before InitGoogleLogging() is written to STDERR
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] foo bar 10 3.4
EDATE TIME__ logging_unittest.cc:LINE] Plog every 2, iteration 1: __SUCCESS__ [0]
EDATE TIME__ logging_unittest.cc:LINE] Log every 3, iteration 1
EDATE TIME__ logging_unittest.cc:LINE] Log every 4, iteration 1
WDATE TIME__ logging_unittest.cc:LINE] Log if every 5, iteration 1
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 1
EDATE TIME__ logging_unittest.cc:LINE] Log if less than 3 every 2, iteration 1
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 2
EDATE TIME__ logging_unittest.cc:LINE] Plog every 2, iteration 3: __ENOENT__ [2]
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 3
EDATE TIME__ logging_unittest.cc:LINE] Log if less than 3 every 2, iteration 3
EDATE TIME__ logging_unittest.cc:LINE] Log every 3, iteration 4
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 4
EDATE TIME__ logging_unittest.cc:LINE] Plog every 2, iteration 5: __EINTR__ [4]
EDATE TIME__ logging_unittest.cc:LINE] Log every 4, iteration 5
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 5
WDATE TIME__ logging_unittest.cc:LINE] Log if every 5, iteration 6
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 6
EDATE TIME__ logging_unittest.cc:LINE] Plog every 2, iteration 7: __ENXIO__ [6]
EDATE TIME__ logging_unittest.cc:LINE] Log every 3, iteration 7
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 7
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 8
EDATE TIME__ logging_unittest.cc:LINE] Plog every 2, iteration 9: __ENOEXEC__ [8]
EDATE TIME__ logging_unittest.cc:LINE] Log every 4, iteration 9
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 9
EDATE TIME__ logging_unittest.cc:LINE] Log every 3, iteration 10
IDATE TIME__ logging_unittest.cc:LINE] Log if every 1, iteration 10
WDATE TIME__ logging_unittest.cc:LINE] log_if this
IDATE TIME__ logging_unittest.cc:LINE] array
IDATE TIME__ logging_unittest.cc:LINE] const array
EDATE TIME__ logging_unittest.cc:LINE] foo 1000 0000001000 3e8
no prefix
IDATE TIME__ logging_unittest.cc:LINE] RAW: foo bar 10 3.400000
WDATE TIME__ logging_unittest.cc:LINE] RAW: array
IDATE TIME__ logging_unittest.cc:LINE] RAW: const array
IDATE TIME__ logging_unittest.cc:LINE] RAW: ptr 0x12345678
IDATE TIME__ logging_unittest.cc:LINE] RAW: ptr __NULLP__
EDATE TIME__ logging_unittest.cc:LINE] RAW: foo 1000 0000001000 3e8
IDATE TIME__ logging_unittest.cc:LINE] RAW: foo 1000
IDATE TIME__ logging_unittest.cc:LINE] RAW: foo 1000
WDATE TIME__ logging_unittest.cc:LINE] RAW: RAW_LOG ERROR: The Message was too long!
IDATE TIME__ logging_unittest.cc:LINE] RAW: RAW_LOG ERROR: The Message was too long!
IDATE TIME__ logging_unittest.cc:LINE] RAW: log
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0 on
IDATE TIME__ logging_unittest.cc:LINE] RAW: log
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 1 on
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 2 on
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 1
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] vlog 1
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 1
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=-1 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=1 logtostderr=0 alsologtostderr=0
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=2 logtostderr=0 alsologtostderr=0
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
EDATE TIME__ logging_unittest.cc:LINE] log error
EDATE TIME__ logging_unittest.cc:LINE] log_if error
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=0 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=1 alsologtostderr=0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=0 alsologtostderr=1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=1 logtostderr=0 alsologtostderr=0
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=3 logtostderr=0 alsologtostderr=1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 0
IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog 1
IDATE TIME__ logging_unittest.cc:LINE] RAW: log info
WDATE TIME__ logging_unittest.cc:LINE] RAW: log warning
EDATE TIME__ logging_unittest.cc:LINE] RAW: log error
IDATE TIME__ logging_unittest.cc:LINE] vlog -1
IDATE TIME__ logging_unittest.cc:LINE] vlog 0
IDATE TIME__ logging_unittest.cc:LINE] vlog 1
IDATE TIME__ logging_unittest.cc:LINE] log info
WDATE TIME__ logging_unittest.cc:LINE] log warning
EDATE TIME__ logging_unittest.cc:LINE] log error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if -1
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 1
IDATE TIME__ logging_unittest.cc:LINE] log_if info
WDATE TIME__ logging_unittest.cc:LINE] log_if warning
EDATE TIME__ logging_unittest.cc:LINE] log_if error
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error expr
IDATE TIME__ logging_unittest.cc:LINE] log_if info every 1 expr
EDATE TIME__ logging_unittest.cc:LINE] log_if error every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IDATE TIME__ logging_unittest.cc:LINE] LOG_STRING: reported info
WDATE TIME__ logging_unittest.cc:LINE] LOG_STRING: reported warning
EDATE TIME__ logging_unittest.cc:LINE] LOG_STRING: reported error
IDATE TIME__ logging_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected info
IDATE TIME__ logging_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected warning
IDATE TIME__ logging_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected error
IDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: collected info
WDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: collected warning
EDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: collected error
IDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: reported info
WDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: reported warning
EDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: reported error
IDATE TIME__ logging_unittest.cc:LINE] Captured by LOG_TO_SINK:
IDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: collected info
WDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: collected warning
EDATE TIME__ logging_unittest.cc:LINE] LOG_TO_SINK: collected error
IDATE TIME__ logging_unittest.cc:LINE] Message 1
IDATE TIME__ logging_unittest.cc:LINE] RAW: Buffering
IDATE TIME__ logging_unittest.cc:LINE] RAW: Buffered
IDATE TIME__ logging_unittest.cc:LINE] RAW: Waiting
IDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Sink got a messages
IDATE TIME__ logging_unittest.cc:LINE] RAW: Waited
IDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: IDATE TIME__ logging_unittest.cc:LINE] Message 1
IDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left
EDATE TIME__ logging_unittest.cc:LINE] Message 2
IDATE TIME__ logging_unittest.cc:LINE] RAW: Buffering
IDATE TIME__ logging_unittest.cc:LINE] RAW: Buffered
IDATE TIME__ logging_unittest.cc:LINE] RAW: Waiting
IDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Sink got a messages
IDATE TIME__ logging_unittest.cc:LINE] RAW: Waited
IDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: EDATE TIME__ logging_unittest.cc:LINE] Message 2
IDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left
WDATE TIME__ logging_unittest.cc:LINE] Message 3
IDATE TIME__ logging_unittest.cc:LINE] RAW: Buffering
IDATE TIME__ logging_unittest.cc:LINE] RAW: Buffered
IDATE TIME__ logging_unittest.cc:LINE] RAW: Waiting
IDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Sink got a messages
IDATE TIME__ logging_unittest.cc:LINE] RAW: Waited
IDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: WDATE TIME__ logging_unittest.cc:LINE] Message 3
IDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left
IDATE TIME__ logging_unittest.cc:LINE] Sink capture: IDATE TIME__ logging_unittest.cc:LINE] Message 1
IDATE TIME__ logging_unittest.cc:LINE] Sink capture: EDATE TIME__ logging_unittest.cc:LINE] Message 2
IDATE TIME__ logging_unittest.cc:LINE] Sink capture: WDATE TIME__ logging_unittest.cc:LINE] Message 3

114
src/raw_logging.cc Normal file
View File

@ -0,0 +1,114 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Maxim Lifantsev
//
// logging_unittest.cc covers the functionality herein
#include "utilities.h"
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include "config.h"
#include "glog/logging.h" // To pick up flag settings etc.
#include "glog/raw_logging.h"
#if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h> // for syscall()
#endif
#include <unistd.h>
#if defined(OS_MACOSX)
#ifndef __DARWIN_UNIX03
#define __DARWIN_UNIX03 // tells libgen.h to define basename()
#endif
#endif // OS_MACOSX
#include <libgen.h> // basename()
_START_GOOGLE_NAMESPACE_
// Data for RawLog__ below. We simply pick up the latest
// time data created by a normal log message to avoid calling
// localtime_r which can allocate memory.
static struct ::tm last_tm_time_for_raw_log;
void RawLog__SetLastTime(const struct ::tm& t) {
memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log));
}
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// If this becomes a problem we should reimplement a subset of vsnprintf
// that does not need locks and malloc.
// Helper for RawLog__ below.
// *DoRawLog writes to *buf of *size and move them past the written portion.
// It returns true iff there was no overflow or error.
static bool DoRawLog(char** buf, int* size, const char* format, ...) {
va_list ap;
va_start(ap, format);
int n = vsnprintf(*buf, *size, format, ap);
va_end(ap);
if (n < 0 || n > *size) return false;
*size -= n;
*buf += n;
return true;
}
// Helper for RawLog__ below.
inline static bool VADoRawLog(char** buf, int* size,
const char* format, va_list ap) {
int n = vsnprintf(*buf, *size, format, ap);
if (n < 0 || n > *size) return false;
*size -= n;
*buf += n;
return true;
}
void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) {
if (!(FLAGS_logtostderr || severity >= FLAGS_stderrthreshold ||
FLAGS_alsologtostderr || !IsGoogleLoggingInitialized())) {
return; // this stderr log message is suppressed
}
// can't call localtime_r here: it can allocate
struct ::tm& t = last_tm_time_for_raw_log;
char buffer[3000]; // 3000 bytes should be enough for everyone... :-)
char* buf = buffer;
int size = sizeof(buffer);
if (is_default_thread()) {
DoRawLog(&buf, &size, "%c%02d%02d %02d%02d%02d %s:%d] RAW: ",
LogSeverityNames[severity][0],
1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
basename(const_cast<char *>(file)), line);
} else {
DoRawLog(&buf, &size, "%c%02d%02d %02d%02d%02d %08x %s:%d] RAW: ",
LogSeverityNames[severity][0],
1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
int(pthread_self()),
basename(const_cast<char *>(file)), line);
}
va_list ap;
va_start(ap, format);
bool no_chop = VADoRawLog(&buf, &size, format, ap);
va_end(ap);
if (no_chop) {
DoRawLog(&buf, &size, "\n");
} else {
DoRawLog(&buf, &size, "RAW_LOG ERROR: The Message was too long!\n");
}
// We make a raw syscall to write directly to the stderr file descriptor,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception).
// We write just once to avoid races with other invocations of RawLog__.
#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)
syscall(SYS_write, STDERR_FILENO, buffer, strlen(buffer));
#else
write(STDERR_FILENO, buffer, strlen(buffer));
#endif
if (severity == FATAL) LogMessage::Fail();
}
_END_GOOGLE_NAMESPACE_

68
src/stacktrace.cc Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2000 - 2007 Google Inc.
// All rights reserved.
//
// Produce stack trace.
//
// There are three different ways we can try to get the stack trace:
//
// 1) Our hand-coded stack-unwinder. This depends on a certain stack
// layout, which is used by gcc (and those systems using a
// gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
// It uses the frame pointer to do its work.
//
// 2) The libunwind library. This is still in development, and as a
// separate library adds a new dependency, abut doesn't need a frame
// pointer. It also doesn't call malloc.
//
// 3) The gdb unwinder -- also the one used by the c++ exception code.
// It's obviously well-tested, but has a fatal flaw: it can call
// malloc() from the unwinder. This is a problem because we're
// trying to use the unwinder to instrument malloc().
//
// Note: if you add a new implementation here, make sure it works
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.
#include "config.h"
// First, the i386 case.
#if defined(__i386__) && __GNUC__ >= 2
# if defined(HAVE_EXECINFO_H)
# include "stacktrace_generic-inl.h"
# elif !defined(NO_FRAME_POINTER)
# include "stacktrace_x86-inl.h"
# endif
// Now, the x86_64 case.
#elif defined(__x86_64__) && __GNUC__ >= 2
# if defined(HAVE_EXECINFO_H)
# include "stacktrace_generic-inl.h"
# elif !defined(NO_FRAME_POINTER)
# include "stacktrace_x86-inl.h"
# elif 1
// This is the unwinder used by gdb, which can call malloc (see above).
# include "stacktrace_x86_64-inl.h"
# elif 0 // We assume libunwind is installed on this machine
// Use the libunwind library.
// There's no way to enable it except for manually
// editing this file (by replacing this "elif 0" with "elif 1", e.g.).
# define UNW_LOCAL_ONLY
# include "stacktrace_libunwind-inl.h"
# elif defined(__linux)
# error Cannnot calculate stack trace: need either libunwind or frame-pointers
# else
# error Cannnot calculate stack trace: need libunwind
# endif
// The PowerPC case
#elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# if defined(HAVE_EXECINFO_H)
# include "stacktrace_generic-inl.h"
# elif defined(STACKTRACE_WITH_FRAME_POINTER)
# include "stacktrace_powerpc-inl.h"
# endif
// OK, those are all the processors we know how to deal with.
#else
# error Cannot calculate stack trace: will need to write for your environment
#endif

68
src/stacktrace.h Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2000 - 2007 Google Inc.
// All rights reserved.
//
// Routines to extract the current stack trace. These functions are
// thread-safe.
#ifndef BASE_STACKTRACE_H_
#define BASE_STACKTRACE_H_
#include "config.h"
_START_GOOGLE_NAMESPACE_
// Skips the most recent "skip_count" stack frames (also skips the
// frame generated for the "GetStackFrames" routine itself), and then
// records the pc values for up to the next "max_depth" frames in
// "pcs", and the corresponding stack frame sizes in "sizes". Returns
// the number of values recorded in "pcs"/"sizes".
//
// Example:
// main() { foo(); }
// foo() { bar(); }
// bar() {
// void* pcs[10];
// int sizes[10];
// int depth = GetStackFrames(pcs, sizes, 10, 1);
// }
//
// The GetStackFrames call will skip the frame for "bar". It will
// return 2 and will produce pc values that map to the following
// procedures:
// pcs[0] foo
// pcs[1] main
// (Actually, there may be a few more entries after "main" to account for
// startup procedures.)
// And corresponding stack frame sizes will also be recorded:
// sizes[0] 16
// sizes[1] 16
// (Stack frame sizes of 16 above are just for illustration purposes.)
// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
// be identified.
//
// This routine may return fewer stack frame entries than are
// available. Also note that "pcs" and "sizes" must both be non-NULL.
extern int GetStackFrames(void** pcs, int* sizes, int max_depth,
int skip_count);
// This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well.
// Example:
// main() { foo(); }
// foo() { bar(); }
// bar() {
// void* result[10];
// int depth = GetStackFrames(result, 10, 1);
// }
//
// This produces:
// result[0] foo
// result[1] main
// .... ...
//
// "result" must not be NULL.
extern int GetStackTrace(void** result, int max_depth, int skip_count);
_END_GOOGLE_NAMESPACE_
#endif // BASE_STACKTRACE_H_

View File

@ -0,0 +1,119 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: Raksit Ashok
//
// Unit test for the GetStackFrames function in stacktrace.cc.
#include <stdio.h>
#include "glog/logging.h"
#include "base/commandlineflags.h"
#include "stacktrace.h"
#include "config.h"
#include "utilities.h"
using std::min;
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE
// Obtain a backtrace of the stack frame sizes, verify that they look sane.
//-----------------------------------------------------------------------//
int CheckFrameSizesLeaf(int32* i); // 8KB frame size.
int CheckFrameSizes2(int32* i); // 4KB
int CheckFrameSizes1(int32* i); // 2KB
int CheckFrameSizes(int32* i); // 1KB
//-----------------------------------------------------------------------//
// The expected frame-sizes in the backtrace.
const int BACKTRACE_STEPS = 4;
int expected_frame_sizes[BACKTRACE_STEPS] = {
1 << 13,
1 << 12,
1 << 11,
1 << 10,
};
//-----------------------------------------------------------------------//
void CheckFrameSizeIsOk(int actual_frame_size, int ref_frame_size) {
// Assume upto 512 bytes of miscellaneous stuff in CheckFrameSizes* frames.
const int misc_frame_size = 512;
CHECK_GE(actual_frame_size, ref_frame_size);
CHECK_LE(actual_frame_size, ref_frame_size + misc_frame_size);
}
//-----------------------------------------------------------------------//
int ATTRIBUTE_NOINLINE CheckFrameSizesLeaf(int32 *i) {
const int DEPTH = 10;
void* pcs[DEPTH];
int frame_sizes[DEPTH];
int size;
int32 j[2048]; // 8KB.
for (int k = 0; k < 2048; k++) j[k] = k + i[k % 1024];
for (int depth = 0; depth < DEPTH; depth++) {
size = GetStackFrames(pcs, frame_sizes, depth, 0);
printf("--- GetStackFrames(..., %d, 0) = %d\n", depth, size);
CHECK_LE(size, depth);
CHECK_GE(size, min(depth, BACKTRACE_STEPS));
for (int k = 0; k < size; k++) {
if (k < BACKTRACE_STEPS)
// GetStackFrames doesn't work correctly if we are using glibc's backtrace.
#ifndef HAVE_EXECINFO_H
CheckFrameSizeIsOk(frame_sizes[k], expected_frame_sizes[k]);
#endif
printf("frame_sizes[%d] = %d\n", k, frame_sizes[k]);
}
}
int sum = 0;
for (int k = 0; k < 2048; k++) sum += j[k];
return sum;
}
//-----------------------------------------------------------------------//
/* Dummy functions to make the frame-size backtrace more interesting. */
int ATTRIBUTE_NOINLINE CheckFrameSizes2(int32* i) {
int32 j[1024]; // 4KB.
for (int k = 0; k < 1024; k++) j[k] = k + i[k % 512];
return CheckFrameSizesLeaf(j) + j[512];
}
int ATTRIBUTE_NOINLINE CheckFrameSizes1(int32* i) {
int32 j[512]; // 2KB.
for (int k = 0; k < 512; k++) j[k] = k + i[k % 256];
return CheckFrameSizes2(j) + j[256];
}
int ATTRIBUTE_NOINLINE CheckFrameSizes(int32* i) {
int32 j[256]; // 1KB.
for (int k = 0; k < 256; k++) j[k] = k + i[k];
return CheckFrameSizes1(j) + j[128];
}
//-----------------------------------------------------------------------//
int main(int argc, char ** argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
int32 i[256]; // 1KB.
for (int j = 0; j < 256; j++) i[j] = j;
int ret = CheckFrameSizes(i);
printf("CheckFrameSizes returned: %d\n", ret);
printf("PASS\n");
return 0;
}
#else
int main() {
printf("PASS (no stacktrace support)\n");
return 0;
}
#endif // HAVE_STACKTRACE

View File

@ -0,0 +1,81 @@
// Copyright 2000 - 2007 Google Inc.
// All rights reserved.
//
// Portable implementation - just use glibc
//
// Note: The glibc implementation may cause a call to malloc.
// This can cause a deadlock in HeapProfiler.
#include <execinfo.h>
#include <string.h>
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64;
void * stack[kStackLength];
int size;
size = backtrace(stack, kStackLength);
skip_count++; // we want to skip the current frame as well
int result_count = size - skip_count;
if (result_count < 0)
result_count = 0;
if (result_count > max_depth)
result_count = max_depth;
for (int i = 0; i < result_count; i++)
result[i] = stack[i + skip_count];
return result_count;
}
// If you change this function, also change GetStackTrace above:
//
// This GetStackFrames routine shares a lot of code with GetStackTrace
// above. This code could have been refactored into a common routine,
// and then both GetStackTrace/GetStackFrames could call that routine.
// There are two problems with that:
//
// (1) The performance of the refactored-code suffers substantially - the
// refactored needs to be able to record the stack trace when called
// from GetStackTrace, and both the stack trace and stack frame sizes,
// when called from GetStackFrames - this introduces enough new
// conditionals that GetStackTrace performance can degrade by as much
// as 50%.
//
// (2) Whether the refactored routine gets inlined into GetStackTrace and
// GetStackFrames depends on the compiler, and we can't guarantee the
// behavior either-way, even with "__attribute__ ((always_inline))"
// or "__attribute__ ((noinline))". But we need this guarantee or the
// frame counts may be off by one.
//
// Both (1) and (2) can be addressed without this code duplication, by
// clever use of template functions, and by defining GetStackTrace and
// GetStackFrames as macros that expand to these template functions.
// However, this approach comes with its own set of problems - namely,
// macros and preprocessor trouble - for example, if GetStackTrace
// and/or GetStackFrames is ever defined as a member functions in some
// class, we are in trouble.
int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
static const int kStackLength = 64;
void * stack[kStackLength];
int size;
size = backtrace(stack, kStackLength);
skip_count++; // we want to skip the current frame as well
int result_count = size - skip_count;
if (result_count < 0)
result_count = 0;
if (result_count > max_depth)
result_count = max_depth;
for (int i = 0; i < result_count; i++)
pcs[i] = stack[i + skip_count];
// No implementation for finding out the stack frame sizes yet.
memset(sizes, 0, sizeof(*sizes) * result_count);
return result_count;
}
_END_GOOGLE_NAMESPACE_

View File

@ -0,0 +1,127 @@
// Copyright 2005 - 2007 Google Inc.
// All rights reserved.
//
// Author: Arun Sharma
//
// Produce stack trace using libunwind
extern "C" {
#include <libunwind.h>
}
#include "base/stacktrace.h"
#include "base/raw_logging.h"
#include "base/spinlock.h"
_START_GOOGLE_NAMESPACE_
// Sometimes, we can try to get a stack trace from within a stack
// trace, because libunwind can call mmap/sbrk (maybe indirectly via
// malloc), and that mmap gets trapped and causes a stack-trace
// request. If were to try to honor that recursive request, we'd end
// up with infinite recursion or deadlock. Luckily, it's safe to
// ignore those subsequent traces. In such cases, we return 0 to
// indicate the situation.
static SpinLock libunwind_lock(SpinLock::LINKER_INITIALIZED);
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void *ip;
int n = 0;
unw_cursor_t cursor;
unw_context_t uc;
if (!libunwind_lock.TryLock()) {
return 0;
}
unw_getcontext(&uc);
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
skip_count++; // Do not include the "GetStackTrace" frame
while (n < max_depth) {
int ret = unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip);
if (ret < 0)
break;
if (skip_count > 0) {
skip_count--;
} else {
result[n++] = ip;
}
ret = unw_step(&cursor);
if (ret <= 0)
break;
}
libunwind_lock.Unlock();
return n;
}
// If you change this function, also change GetStackTrace above:
//
// This GetStackFrames routine shares a lot of code with GetStackTrace
// above. This code could have been refactored into a common routine,
// and then both GetStackTrace/GetStackFrames could call that routine.
// There are two problems with that:
//
// (1) The performance of the refactored-code suffers substantially - the
// refactored needs to be able to record the stack trace when called
// from GetStackTrace, and both the stack trace and stack frame sizes,
// when called from GetStackFrames - this introduces enough new
// conditionals that GetStackTrace performance can degrade by as much
// as 50%.
//
// (2) Whether the refactored routine gets inlined into GetStackTrace and
// GetStackFrames depends on the compiler, and we can't guarantee the
// behavior either-way, even with "__attribute__ ((always_inline))"
// or "__attribute__ ((noinline))". But we need this guarantee or the
// frame counts may be off by one.
//
// Both (1) and (2) can be addressed without this code duplication, by
// clever use of template functions, and by defining GetStackTrace and
// GetStackFrames as macros that expand to these template functions.
// However, this approach comes with its own set of problems - namely,
// macros and preprocessor trouble - for example, if GetStackTrace
// and/or GetStackFrames is ever defined as a member functions in some
// class, we are in trouble.
int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
void *ip;
int n = 0;
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t sp = 0, next_sp = 0;
if (!libunwind_lock.TryLock()) {
return 0;
}
unw_getcontext(&uc);
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
skip_count++; // Do not include the "GetStackFrames" frame
while (skip_count--) {
if (unw_step(&cursor) <= 0 ||
unw_get_reg(&cursor, UNW_REG_SP, &next_sp) < 0) {
goto out;
}
}
while (n < max_depth) {
sp = next_sp;
if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0)
break;
if (unw_step(&cursor) <= 0 ||
unw_get_reg(&cursor, UNW_REG_SP, &next_sp)) {
// We couldn't step any further (possibly because we reached _start).
// Provide the last good PC we've got, and get out.
sizes[n] = 0;
pcs[n++] = ip;
break;
}
sizes[n] = next_sp - sp;
pcs[n++] = ip;
}
out:
libunwind_lock.Unlock();
return n;
}
_END_GOOGLE_NAMESPACE_

View File

@ -0,0 +1,182 @@
// Copyright 2007 and onwards Google Inc.
// All rights reserved.
//
// Author: Craig Silverstein
//
// Produce stack trace. I'm guessing (hoping!) the code is much like
// for x86. For apple machines, at least, it seems to be; see
// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
#include <stdio.h>
#include <stdint.h> // for uintptr_t
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = (void **) *old_sp;
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) {
// With the stack growing downwards, older stack frame must be
// at a greater address that the current one.
if (new_sp <= old_sp) return NULL;
// Assume stack frames larger than 100,000 bytes are bogus.
if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
} else {
// In the non-strict mode, allow discontiguous stack frames.
// (alternate-signal-stacks for example).
if (new_sp == old_sp) return NULL;
// And allow frames upto about 1MB.
if ((new_sp > old_sp)
&& ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
}
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
return new_sp;
}
// This ensures that GetStackTrace stes up the Link Register properly.
void StacktracePowerPCDummyFunction() __attribute__((noinline));
void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
// different asm syntax. I don't know quite the best way to discriminate
// systems using the old as from the new one; I've gone with __APPLE__.
#ifdef __APPLE__
__asm__ volatile ("mr %0,r1" : "=r" (sp));
#else
__asm__ volatile ("mr %0,1" : "=r" (sp));
#endif
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
// entry that holds the return address of the subroutine call (what
// instruction we run after our function finishes). This is the
// same as the stack-pointer of our parent routine, which is what we
// want here. While the compiler will always(?) set up LR for
// subroutine calls, it may not for leaf functions (such as this one).
// This routine forces the compiler (at least gcc) to push it anyway.
StacktracePowerPCDummyFunction();
// The LR save area is used by the callee, so the top entry is bogus.
skip_count++;
int n = 0;
while (sp && n < max_depth) {
if (skip_count > 0) {
skip_count--;
} else {
// PowerPC has 3 main ABIs, which say where in the stack the
// Link Register is. For DARWIN and AIX (used by apple and
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
// it's in sp[1].
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
result[n++] = *(sp+2);
#elif defined(_CALL_SYSV)
result[n++] = *(sp+1);
#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc.
result[n++] = *(sp+2);
#elif defined(__linux)
// This check is in case the compiler doesn't define _CALL_SYSV.
result[n++] = *(sp+1);
#else
#error Need to specify the PPC ABI for your archiecture.
#endif
}
// Use strict unwinding rules.
sp = NextStackFrame<true>(sp);
}
return n;
}
// If you change this function, also change GetStackTrace above:
//
// This GetStackFrames routine shares a lot of code with GetStackTrace
// above. This code could have been refactored into a common routine,
// and then both GetStackTrace/GetStackFrames could call that routine.
// There are two problems with that:
//
// (1) The performance of the refactored-code suffers substantially - the
// refactored needs to be able to record the stack trace when called
// from GetStackTrace, and both the stack trace and stack frame sizes,
// when called from GetStackFrames - this introduces enough new
// conditionals that GetStackTrace performance can degrade by as much
// as 50%.
//
// (2) Whether the refactored routine gets inlined into GetStackTrace and
// GetStackFrames depends on the compiler, and we can't guarantee the
// behavior either-way, even with "__attribute__ ((always_inline))"
// or "__attribute__ ((noinline))". But we need this guarantee or the
// frame counts may be off by one.
//
// Both (1) and (2) can be addressed without this code duplication, by
// clever use of template functions, and by defining GetStackTrace and
// GetStackFrames as macros that expand to these template functions.
// However, this approach comes with its own set of problems - namely,
// macros and preprocessor trouble - for example, if GetStackTrace
// and/or GetStackFrames is ever defined as a member functions in some
// class, we are in trouble.
int GetStackFrames(void** pcs, int *sizes, int max_depth, int skip_count) {
void **sp;
#ifdef __APPLE__
__asm__ volatile ("mr %0,r1" : "=r" (sp));
#else
__asm__ volatile ("mr %0,1" : "=r" (sp));
#endif
StacktracePowerPCDummyFunction();
// Note we do *not* increment skip_count here for the SYSV ABI. If
// we did, the list of stack frames wouldn't properly match up with
// the list of return addresses. Note this means the top pc entry
// is probably bogus for linux/ppc (and other SYSV-ABI systems).
int n = 0;
while (sp && n < max_depth) {
// The GetStackFrames routine is called when we are in some
// informational context (the failure signal handler for example).
// Use the non-strict unwinding rules to produce a stack trace
// that is as complete as possible (even if it contains a few bogus
// entries in some rare cases).
void **next_sp = NextStackFrame<false>(sp);
if (skip_count > 0) {
skip_count--;
} else {
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
pcs[n++] = *(sp+2);
#elif defined(_CALL_SYSV)
pcs[n++] = *(sp+1);
#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc.
pcs[n++] = *(sp+2);
#elif defined(__linux)
// This check is in case the compiler doesn't define _CALL_SYSV.
pcs[n++] = *(sp+1);
#else
#error Need to specify the PPC ABI for your archiecture.
#endif
if (next_sp > sp) {
sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
} else {
// A frame-size of 0 is used to indicate unknown frame size.
sizes[n] = 0;
}
n++;
}
sp = next_sp;
}
return n;
}
_END_GOOGLE_NAMESPACE_

124
src/stacktrace_unittest.cc Normal file
View File

@ -0,0 +1,124 @@
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "utilities.h"
#include "base/commandlineflags.h"
#include "glog/logging.h"
#include "stacktrace.h"
#ifdef HAVE_EXECINFO_H
# include <execinfo.h>
#endif
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE
// Obtain a backtrace, verify that the expected callers are present in the
// backtrace, and maybe print the backtrace to stdout.
//-----------------------------------------------------------------------//
void CheckStackTraceLeaf();
void CheckStackTrace4(int i);
void CheckStackTrace3(int i);
void CheckStackTrace2(int i);
void CheckStackTrace1(int i);
void CheckStackTrace(int i);
//-----------------------------------------------------------------------//
// The sequence of functions whose return addresses we expect to see in the
// backtrace.
const int BACKTRACE_STEPS = 6;
void * expected_stack[BACKTRACE_STEPS] = {
(void *) &CheckStackTraceLeaf,
(void *) &CheckStackTrace4,
(void *) &CheckStackTrace3,
(void *) &CheckStackTrace2,
(void *) &CheckStackTrace1,
(void *) &CheckStackTrace,
};
// Depending on the architecture/compiler/libraries, (not sure which)
// the current function may or may not appear in the backtrace.
// For gcc-2:
//
// stack[0] is ret addr within CheckStackTrace4
// stack[1] is ret addr within CheckStackTrace3
// stack[2] is ret addr within CheckStackTrace2
// stack[3] is ret addr within CheckStackTrace1
// stack[4] is ret addr within CheckStackTrace
//
// For gcc3-k8:
//
// stack[0] is ret addr within CheckStackTraceLeaf
// stack[1] is ret addr within CheckStackTrace4
// ...
// stack[5] is ret addr within CheckStackTrace
//-----------------------------------------------------------------------//
const int kMaxFnLen = 0x40; // assume relevant functions are only this long
void CheckRetAddrIsInFunction( void * ret_addr, void * function_start_addr)
{
CHECK_GE(ret_addr, function_start_addr);
CHECK_LE(ret_addr, (void *) ((char *) function_start_addr + kMaxFnLen));
}
//-----------------------------------------------------------------------//
void CheckStackTraceLeaf(void) {
const int STACK_LEN = 10;
void *stack[STACK_LEN];
int size;
size = GetStackTrace(stack, STACK_LEN, 0);
printf("Obtained %d stack frames.\n", size);
CHECK_LE(size, STACK_LEN);
if (1) {
#ifdef HAVE_EXECINFO_H
char **strings = backtrace_symbols(stack, size);
printf("Obtained %d stack frames.\n", size);
for (int i = 0; i < size; i++)
printf("%s %p\n", strings[i], stack[i]);
printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
free(strings);
#endif
}
for (int i = 0; i < BACKTRACE_STEPS; i++) {
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
i, expected_stack[i],
reinterpret_cast<char*>(expected_stack[i]) + kMaxFnLen, stack[i]);
CheckRetAddrIsInFunction(stack[i], expected_stack[i]);
printf("OK\n");
}
}
//-----------------------------------------------------------------------//
/* Dummy functions to make the backtrace more interesting. */
void CheckStackTrace4(int i) { for (int j = i; j >= 0; j--) CheckStackTraceLeaf(); }
void CheckStackTrace3(int i) { for (int j = i; j >= 0; j--) CheckStackTrace4(j); }
void CheckStackTrace2(int i) { for (int j = i; j >= 0; j--) CheckStackTrace3(j); }
void CheckStackTrace1(int i) { for (int j = i; j >= 0; j--) CheckStackTrace2(j); }
void CheckStackTrace(int i) { for (int j = i; j >= 0; j--) CheckStackTrace1(j); }
//-----------------------------------------------------------------------//
int main(int argc, char ** argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
CheckStackTrace(0);
printf("PASS\n");
return 0;
}
#else
int main() {
printf("PASS (no stacktrace support)\n");
return 0;
}
#endif // HAVE_STACKTRACE

197
src/stacktrace_x86-inl.h Normal file
View File

@ -0,0 +1,197 @@
// Copyright 2000 - 2007 Google Inc.
// All rights reserved.
//
// Produce stack trace
#include <stdint.h> // for uintptr_t
#include "utilities.h" // for OS_* macros
#if !defined(OS_WINDOWS)
#include <unistd.h>
#include <sys/mman.h>
#endif
#include <stdio.h> // for NULL
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = (void **) *old_sp;
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) {
// With the stack growing downwards, older stack frame must be
// at a greater address that the current one.
if (new_sp <= old_sp) return NULL;
// Assume stack frames larger than 100,000 bytes are bogus.
if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
} else {
// In the non-strict mode, allow discontiguous stack frames.
// (alternate-signal-stacks for example).
if (new_sp == old_sp) return NULL;
// And allow frames upto about 1MB.
if ((new_sp > old_sp)
&& ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
}
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
#ifdef __i386__
// On 64-bit machines, the stack pointer can be very close to
// 0xffffffff, so we explicitly check for a pointer into the
// last two pages in the address space
if ((uintptr_t)new_sp >= 0xffffe000) return NULL;
#endif
#if !defined(OS_WINDOWS)
if (!STRICT_UNWINDING) {
// Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
// on AMD-based machines with VDSO-enabled kernels.
// Make an extra sanity check to insure new_sp is readable.
// Note: NextStackFrame<false>() is only called while the program
// is already on its last leg, so it's ok to be slow here.
static int page_size = getpagesize();
void *new_sp_aligned = (void *)((uintptr_t)new_sp & ~(page_size - 1));
if (msync(new_sp_aligned, page_size, MS_ASYNC) == -1)
return NULL;
}
#endif
return new_sp;
}
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
#ifdef __i386__
// Stack frame format:
// sp[0] pointer to previous frame
// sp[1] caller address
// sp[2] first argument
// ...
sp = (void **)&result - 2;
#endif
#ifdef __x86_64__
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
unsigned long rbp;
// Move the value of the register %rbp into the local variable rbp.
// We need 'volatile' to prevent this instruction from getting moved
// around during optimization to before function prologue is done.
// An alternative way to achieve this
// would be (before this __asm__ instruction) to call Noop() defined as
// static void Noop() __attribute__ ((noinline)); // prevent inlining
// static void Noop() { asm(""); } // prevent optimizing-away
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
// Arguments are passed in registers on x86-64, so we can't just
// offset from &result
sp = (void **) rbp;
#endif
int n = 0;
while (sp && n < max_depth) {
if (*(sp+1) == (void *)0) {
// In 64-bit code, we often see a frame that
// points to itself and has a return address of 0.
break;
}
if (skip_count > 0) {
skip_count--;
} else {
result[n++] = *(sp+1);
}
// Use strict unwinding rules.
sp = NextStackFrame<true>(sp);
}
return n;
}
// If you change this function, also change GetStackTrace above:
//
// This GetStackFrames routine shares a lot of code with GetStackTrace
// above. This code could have been refactored into a common routine,
// and then both GetStackTrace/GetStackFrames could call that routine.
// There are two problems with that:
//
// (1) The performance of the refactored-code suffers substantially - the
// refactored needs to be able to record the stack trace when called
// from GetStackTrace, and both the stack trace and stack frame sizes,
// when called from GetStackFrames - this introduces enough new
// conditionals that GetStackTrace performance can degrade by as much
// as 50%.
//
// (2) Whether the refactored routine gets inlined into GetStackTrace and
// GetStackFrames depends on the compiler, and we can't guarantee the
// behavior either-way, even with "__attribute__ ((always_inline))"
// or "__attribute__ ((noinline))". But we need this guarantee or the
// frame counts may be off by one.
//
// Both (1) and (2) can be addressed without this code duplication, by
// clever use of template functions, and by defining GetStackTrace and
// GetStackFrames as macros that expand to these template functions.
// However, this approach comes with its own set of problems - namely,
// macros and preprocessor trouble - for example, if GetStackTrace
// and/or GetStackFrames is ever defined as a member functions in some
// class, we are in trouble.
int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
void **sp;
#ifdef __i386__
// Stack frame format:
// sp[0] pointer to previous frame
// sp[1] caller address
// sp[2] first argument
// ...
sp = (void **)&pcs - 2;
#endif
#ifdef __x86_64__
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
unsigned long rbp;
// Move the value of the register %rbp into the local variable rbp.
// We need 'volatile' to prevent this instruction from getting moved
// around during optimization to before function prologue is done.
// An alternative way to achieve this
// would be (before this __asm__ instruction) to call Noop() defined as
// static void Noop() __attribute__ ((noinline)); // prevent inlining
// static void Noop() { asm(""); } // prevent optimizing-away
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
// Arguments are passed in registers on x86-64, so we can't just
// offset from &pcs
sp = (void **) rbp;
#endif
int n = 0;
while (sp && n < max_depth) {
if (*(sp+1) == (void *)0) {
// In 64-bit code, we often see a frame that
// points to itself and has a return address of 0.
break;
}
// The GetStackFrames routine is called when we are in some
// informational context (the failure signal handler for example).
// Use the non-strict unwinding rules to produce a stack trace
// that is as complete as possible (even if it contains a few bogus
// entries in some rare cases).
void **next_sp = NextStackFrame<false>(sp);
if (skip_count > 0) {
skip_count--;
} else {
pcs[n] = *(sp+1);
if (next_sp > sp) {
sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
} else {
// A frame-size of 0 is used to indicate unknown frame size.
sizes[n] = 0;
}
n++;
}
sp = next_sp;
}
return n;
}
_END_GOOGLE_NAMESPACE_

127
src/stacktrace_x86_64-inl.h Normal file
View File

@ -0,0 +1,127 @@
// Copyright 2005 - 2007 Google Inc.
// All rights reserved.
//
// Author: Arun Sharma
//
// Produce stack trace using libgcc
extern "C" {
#include <stdlib.h> // for NULL
#include <unwind.h> // ABI defined unwinder
}
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
typedef struct {
void **result;
int max_depth;
int skip_count;
int count;
} trace_arg_t;
// Workaround for the malloc() in _Unwind_Backtrace() issue.
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context *uc, void *opq) {
return _URC_NO_REASON;
}
// This code is not considered ready to run until
// static initializers run so that we are guaranteed
// that any malloc-related initialization is done.
static bool ready_to_run = false;
class StackTraceInit {
public:
StackTraceInit() {
// Extra call to force initialization
_Unwind_Backtrace(nop_backtrace, NULL);
ready_to_run = true;
}
};
static StackTraceInit module_initializer; // Force initialization
static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
trace_arg_t *targ = (trace_arg_t *) opq;
if (targ->skip_count > 0) {
targ->skip_count--;
} else {
targ->result[targ->count++] = (void *) _Unwind_GetIP(uc);
}
if (targ->count == targ->max_depth)
return _URC_END_OF_STACK;
return _URC_NO_REASON;
}
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
if (!ready_to_run)
return 0;
trace_arg_t targ;
skip_count += 1; // Do not include the "GetStackTrace" frame
targ.result = result;
targ.max_depth = max_depth;
targ.skip_count = skip_count;
targ.count = 0;
_Unwind_Backtrace(GetOneFrame, &targ);
return targ.count;
}
// If you change this function, also change GetStackTrace above:
//
// This GetStackFrames routine shares a lot of code with GetStackTrace
// above. This code could have been refactored into a common routine,
// and then both GetStackTrace/GetStackFrames could call that routine.
// There are two problems with that:
//
// (1) The performance of the refactored-code suffers substantially - the
// refactored needs to be able to record the stack trace when called
// from GetStackTrace, and both the stack trace and stack frame sizes,
// when called from GetStackFrames - this introduces enough new
// conditionals that GetStackTrace performance can degrade by as much
// as 50%.
//
// (2) Whether the refactored routine gets inlined into GetStackTrace and
// GetStackFrames depends on the compiler, and we can't guarantee the
// behavior either-way, even with "__attribute__ ((always_inline))"
// or "__attribute__ ((noinline))". But we need this guarantee or the
// frame counts may be off by one.
//
// Both (1) and (2) can be addressed without this code duplication, by
// clever use of template functions, and by defining GetStackTrace and
// GetStackFrames as macros that expand to these template functions.
// However, this approach comes with its own set of problems - namely,
// macros and preprocessor trouble - for example, if GetStackTrace
// and/or GetStackFrames is ever defined as a member functions in some
// class, we are in trouble.
int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
if (!ready_to_run)
return 0;
trace_arg_t targ;
skip_count += 1; // Do not include the "GetStackFrames" frame
targ.result = pcs;
targ.max_depth = max_depth;
targ.skip_count = skip_count;
targ.count = 0;
_Unwind_Backtrace(GetOneFrame, &targ);
// No implementation for finding out the stack frame sizes yet.
memset(sizes, 0, sizeof(*sizes) * targ.count);
return targ.count;
}
_END_GOOGLE_NAMESPACE_

164
src/stl_logging_unittest.cc Normal file
View File

@ -0,0 +1,164 @@
// Copyright 2003 Google, Inc.
// All Rights Reserved.
#include "config.h"
#ifdef HAVE_USING_OPERATOR
#include "glog/stl_logging.h"
#include <iostream>
#include <map>
#include <string>
#include <strstream>
#include <vector>
#ifdef __GNUC__
# include <ext/hash_map>
# include <ext/hash_set>
#endif
#include "glog/logging.h"
#include "googletest.h"
using namespace std;
#ifdef __GNUC__
using namespace __gnu_cxx;
#endif
struct user_hash {
size_t operator()(int x) const { return x; }
};
void TestSTLLogging() {
{
// Test a sequence.
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
// Just ostrstream s1; leaks heap.
ss << v << ends;
CHECK_STREQ(ss.str(), "10 20 30");
vector<int> copied_v(v);
CHECK_EQ(v, copied_v); // This must compile.
}
{
// Test a sorted pair associative container.
map< int, string > m;
m[20] = "twenty";
m[10] = "ten";
m[30] = "thirty";
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
ss << m << ends;
CHECK_STREQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
map< int, string > copied_m(m);
CHECK_EQ(m, copied_m); // This must compile.
}
#ifdef __GNUC__
{
// Test a hashed simple associative container.
hash_set<int> hs;
hs.insert(10);
hs.insert(20);
hs.insert(30);
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
ss << hs << ends;
CHECK_STREQ(ss.str(), "10 20 30");
hash_set<int> copied_hs(hs);
CHECK_EQ(hs, copied_hs); // This must compile.
}
#endif
#ifdef __GNUC__
{
// Test a hashed pair associative container.
hash_map<int, string> hm;
hm[10] = "ten";
hm[20] = "twenty";
hm[30] = "thirty";
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
ss << hm << ends;
CHECK_STREQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
hash_map<int, string> copied_hm(hm);
CHECK_EQ(hm, copied_hm); // this must compile
}
#endif
{
// Test a long sequence.
vector<int> v;
string expected;
for (int i = 0; i < 100; i++) {
v.push_back(i);
if (i > 0) expected += ' ';
char buf[256];
sprintf(buf, "%d", i);
expected += buf;
}
v.push_back(100);
expected += " ...";
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
ss << v << ends;
CHECK_STREQ(ss.str(), expected.c_str());
}
{
// Test a sorted pair associative container.
// Use a non-default comparison functor.
map< int, string, greater<int> > m;
m[20] = "twenty";
m[10] = "ten";
m[30] = "thirty";
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
ss << m << ends;
CHECK_STREQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
map< int, string, greater<int> > copied_m(m);
CHECK_EQ(m, copied_m); // This must compile.
}
#ifdef __GNUC__
{
// Test a hashed simple associative container.
// Use a user defined hash function.
hash_set<int, user_hash> hs;
hs.insert(10);
hs.insert(20);
hs.insert(30);
char ss_buf[1000];
ostrstream ss(ss_buf, sizeof(ss_buf));
ss << hs << ends;
CHECK_STREQ(ss.str(), "10 20 30");
hash_set<int, user_hash> copied_hs(hs);
CHECK_EQ(hs, copied_hs); // This must compile.
}
#endif
}
int main(int argc, char** argv) {
TestSTLLogging();
std::cout << "PASS\n";
return 0;
}
#else
#include <iostream>
int main(int argc, char** argv) {
std::cout << "We don't support stl_logging for this compiler.\n"
<< "(we need compiler support of 'using ::operator<<' "
<< "for this feature.)\n";
return 0;
}
#endif // HAVE_USING_OPERATOR

613
src/symbolize.cc Normal file
View File

@ -0,0 +1,613 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Satoru Takabayashi
// Stack-footprint reduction work done by Raksit Ashok
//
// Implementation note:
//
// We don't use heaps but only use stacks. We want to reduce the
// stack consumption so that the symbolizer can run on small stacks.
//
// Here are some numbers collected with GCC 4.1.0 on x86:
// - sizeof(Elf32_Sym) = 16
// - sizeof(Elf32_Shdr) = 40
// - sizeof(Elf64_Sym) = 24
// - sizeof(Elf64_Shdr) = 64
//
// This implementation is intended to be async-signal-safe but uses
// some functions which are not guaranteed to be so, such as memchr()
// and memmove(). We assume they are async-signal-safe.
//
#if defined(__ELF__) // defined by gcc on Linux
#include <dlfcn.h>
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <link.h> // For ElfW() macro.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "symbolize.h"
#include "demangle.h"
#include "config.h"
#include "utilities.h"
#include "glog/raw_logging.h"
// Re-runs fn until it doesn't cause EINTR.
#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
_START_GOOGLE_NAMESPACE_
// We don't use assert() since it's not guaranteed to be
// async-signal-safe. Instead we define a minimal assertion
// macro. So far, we don't need pretty printing for __FILE__, etc.
// A wrapper for abort() to make it callable in ? :.
static int AssertFail() {
abort();
return 0; // Should not reach.
}
#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
// Read up to "count" bytes from file descriptor "fd" into the buffer
// starting at "buf" while handling short reads and EINTR. On
// success, return the number of bytes read. Otherwise, return -1.
static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
SAFE_ASSERT(fd >= 0);
SAFE_ASSERT(count >= 0 && count <= SSIZE_MAX);
char *buf0 = reinterpret_cast<char *>(buf);
ssize_t num_bytes = 0;
while (num_bytes < count) {
ssize_t len;
NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
if (len < 0) { // There was an error other than EINTR.
return -1;
}
if (len == 0) { // Reached EOF.
break;
}
num_bytes += len;
}
SAFE_ASSERT(num_bytes <= count);
return num_bytes;
}
// Read up to "count" bytes from "offset" in the file pointed by file
// descriptor "fd" into the buffer starting at "buf". On success,
// return the number of bytes read. Otherwise, return -1.
static ssize_t ReadFromOffset(const int fd, void *buf,
const size_t count, const off_t offset) {
off_t off = lseek(fd, offset, SEEK_SET);
if (off == (off_t)-1) {
return -1;
}
return ReadPersistent(fd, buf, count);
}
// Try reading exactly "count" bytes from "offset" bytes in a file
// pointed by "fd" into the buffer starting at "buf" while handling
// short reads and EINTR. On success, return true. Otherwise, return
// false.
static bool ReadFromOffsetExact(const int fd, void *buf,
const size_t count, const off_t offset) {
ssize_t len = ReadFromOffset(fd, buf, count, offset);
return len == count;
}
// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
static int FileGetElfType(const int fd) {
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return -1;
}
if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
return -1;
}
return elf_header.e_type;
}
// Read the section headers in the given ELF binary, and if a section
// of the specified type is found, set the output to this section header
// and return true. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool
GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
ElfW(Word) type, ElfW(Shdr) *out) {
// Read at most 16 section headers at a time to save read calls.
ElfW(Shdr) buf[16];
for (int i = 0; i < sh_num;) {
const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
const ssize_t num_bytes_to_read =
(sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
sh_offset + i * sizeof(buf[0]));
SAFE_ASSERT(len % sizeof(buf[0]) == 0);
const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
for (int j = 0; j < num_headers_in_buf; ++j) {
if (buf[j].sh_type == type) {
*out = buf[j];
return true;
}
}
i += num_headers_in_buf;
}
return false;
}
// There is no particular reason to limit section name to 63 characters,
// but there has (as yet) been no need for anything longer either.
const int kMaxSectionNameLen = 64;
// name_len should include terminating '\0'.
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out) {
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return false;
}
ElfW(Shdr) shstrtab;
off_t shstrtab_offset = (elf_header.e_shoff +
elf_header.e_shentsize * elf_header.e_shstrndx);
if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
return false;
}
for (int i = 0; i < elf_header.e_shnum; ++i) {
off_t section_header_offset = (elf_header.e_shoff +
elf_header.e_shentsize * i);
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
return false;
}
char header_name[kMaxSectionNameLen];
if (sizeof(header_name) < name_len) {
RAW_LOG(WARNING, "Section name '%s' is too long (%"PRIuS"); "
"section will not be found (even if present).", name, name_len);
// No point in even trying.
return false;
}
off_t name_offset = shstrtab.sh_offset + out->sh_name;
ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
if (n_read == -1) {
return false;
} else if (n_read != name_len) {
// Short read -- name could be at end of file.
continue;
}
if (memcmp(header_name, name, name_len) == 0) {
return true;
}
}
return false;
}
// Read a symbol table and look for the symbol containing the
// pc. Iterate over symbols in a symbol table and look for the symbol
// containing "pc". On success, return true and write the symbol name
// to out. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool
FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
uint64_t symbol_offset, const ElfW(Shdr) *strtab,
const ElfW(Shdr) *symtab) {
if (symtab == NULL) {
return false;
}
const int num_symbols = symtab->sh_size / symtab->sh_entsize;
for (int i = 0; i < num_symbols;) {
off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
// If we are reading Elf64_Sym's, we want to limit this array to
// 32 elements (to keep stack consumption low), otherwise we can
// have a 64 element Elf32_Sym array.
#if __WORDSIZE == 64
#define NUM_SYMBOLS 32
#else
#define NUM_SYMBOLS 64
#endif
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
ElfW(Sym) buf[NUM_SYMBOLS];
const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
SAFE_ASSERT(len % sizeof(buf[0]) == 0);
const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
for (int j = 0; j < num_symbols_in_buf; ++j) {
const ElfW(Sym)& symbol = buf[j];
uint64_t start_address = symbol.st_value;
start_address += symbol_offset;
uint64_t end_address = start_address + symbol.st_size;
if (symbol.st_value != 0 && // Skip null value symbols.
symbol.st_shndx != 0 && // Skip undefined symbols.
start_address <= pc && pc < end_address) {
ssize_t len1 = ReadFromOffset(fd, out, out_size,
strtab->sh_offset + symbol.st_name);
if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
return false;
}
return true; // Obtained the symbol name.
}
}
i += num_symbols_in_buf;
}
return false;
}
// Get the symbol name of "pc" from the file pointed by "fd". Process
// both regular and dynamic symbol tables if necessary. On success,
// write the symbol name to "out" and return true. Otherwise, return
// false.
static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
char *out, int out_size,
uint64_t map_start_address) {
// Read the ELF header.
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return false;
}
uint64_t symbol_offset = 0;
if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
symbol_offset = map_start_address;
}
ElfW(Shdr) symtab, strtab;
// Consult a regular symbol table first.
if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_SYMTAB, &symtab)) {
return false;
}
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
symtab.sh_link * sizeof(symtab))) {
return false;
}
if (FindSymbol(pc, fd, out, out_size, symbol_offset,
&strtab, &symtab)) {
return true; // Found the symbol in a regular 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,
SHT_DYNSYM, &symtab)) {
return false;
}
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
symtab.sh_link * sizeof(symtab))) {
return false;
}
if (FindSymbol(pc, fd, out, out_size, symbol_offset,
&strtab, &symtab)) {
return true; // Found the symbol in a dynamic symbol table.
}
return false;
}
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) {
NO_INTR(close(fd_));
}
}
int get() { return fd_; }
private:
explicit FileDescriptor(const FileDescriptor&);
void operator=(const FileDescriptor&);
};
// Helper class for reading lines from file.
//
// 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()
// and snprintf().
class LineReader {
public:
explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
}
// Read '\n'-terminated line from file. On success, modify "bol"
// and "eol", then return true. Otherwise, return false.
//
// Note: if the last line doesn't end with '\n', the line will be
// dropped. It's an intentional behavior to make the code simple.
bool ReadLine(const char **bol, const char **eol) {
if (BufferIsEmpty()) { // First time.
const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
if (num_bytes <= 0) { // EOF or error.
return false;
}
eod_ = buf_ + num_bytes;
bol_ = buf_;
} else {
bol_ = eol_ + 1; // Advance to the next line in the buffer.
SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
if (!HasCompleteLine()) {
const int incomplete_line_length = eod_ - bol_;
// Move the trailing incomplete line to the beginning.
memmove(buf_, bol_, incomplete_line_length);
// Read text from file and append it.
char * const append_pos = buf_ + incomplete_line_length;
const int capacity_left = buf_len_ - incomplete_line_length;
const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
capacity_left);
if (num_bytes <= 0) { // EOF or error.
return false;
}
eod_ = append_pos + num_bytes;
bol_ = buf_;
}
}
eol_ = FindLineFeed();
if (eol_ == NULL) { // '\n' not found. Malformed line.
return false;
}
*eol_ = '\0'; // Replace '\n' with '\0'.
*bol = bol_;
*eol = eol_;
return true;
}
// Beginning of line.
const char *bol() {
return bol_;
}
// End of line.
const char *eol() {
return eol_;
}
private:
explicit LineReader(const LineReader&);
void operator=(const LineReader&);
char *FindLineFeed() {
return reinterpret_cast<char *>
(memchr(reinterpret_cast<const void *>(bol_), '\n', eod_ - bol_));
}
bool BufferIsEmpty() {
return buf_ == eod_;
}
bool HasCompleteLine() {
return !BufferIsEmpty() && FindLineFeed() != NULL;
}
const int fd_;
char * const buf_;
const int buf_len_;
const char *bol_;
char *eol_;
const char *eod_; // End of data in "buf_".
};
} // namespace
// Place the hex number read from "start" into "*hex". The pointer to
// the first non-hex character or "end" is returned.
static char *GetHex(const char *start, const char *end, uint64_t *hex) {
*hex = 0;
const char *p;
for (p = start; p < end; ++p) {
int ch = *p;
if ((ch >= '0' && ch <= '9') ||
(ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
*hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
} else { // Encountered the first non-hex character.
break;
}
}
SAFE_ASSERT(p <= end);
return const_cast<char *>(p);
}
// Search for the object file (from /proc/self/maps) that contains
// the specified pc. If found, open this file and return the file handle,
// and also set start_address to the start address of where this object
// file is mapped to in memory. Otherwise, return -1.
static ATTRIBUTE_NOINLINE int
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t &start_address) {
int object_fd;
// Open /proc/self/maps.
int maps_fd;
NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
FileDescriptor wrapped_maps_fd(maps_fd);
if (wrapped_maps_fd.get() < 0) {
return -1;
}
// Iterate over maps and look for the map containing the pc. Then
// look into the symbol tables inside.
char buf[1024]; // Big enough for line of sane /proc/self/maps
LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
while (true) {
const char *cursor;
const char *eol;
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
return -1;
}
// Start parsing line in /proc/self/maps. Here is an example:
//
// 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
//
// We want start address (08048000), end address (0804c000), flags
// (r-xp) and file name (/bin/cat).
// Read start address.
cursor = GetHex(cursor, eol, &start_address);
if (cursor == eol || *cursor != '-') {
return -1; // Malformed line.
}
++cursor; // Skip '-'.
// Read end address.
uint64_t end_address;
cursor = GetHex(cursor, eol, &end_address);
if (cursor == eol || *cursor != ' ') {
return -1; // Malformed line.
}
++cursor; // Skip ' '.
// Check start and end addresses.
if (!(start_address <= pc && pc < end_address)) {
continue; // We skip this map. PC isn't in this map.
}
// Read flags. Skip flags until we encounter a space or eol.
const char * const flags_start = cursor;
while (cursor < eol && *cursor != ' ') {
++cursor;
}
// We expect at least four letters for flags (ex. "r-xp").
if (cursor == eol || cursor < flags_start + 4) {
return -1; // Malformed line.
}
// Check flags. We are only interested in "r-x" maps.
if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
continue; // We skip this map.
}
++cursor; // Skip ' '.
// Skip to file name. "cursor" now points to file offset. We need to
// skip at least three spaces for file offset, dev, and inode.
int num_spaces = 0;
while (cursor < eol) {
if (*cursor == ' ') {
++num_spaces;
} else if (num_spaces >= 3) {
// The first non-space character after skipping three spaces
// is the beginning of the file name.
break;
}
++cursor;
}
if (cursor == eol) {
return -1; // Malformed line.
}
// Finally, "cursor" now points to file name of our interest.
NO_INTR(object_fd = open(cursor, O_RDONLY));
if (object_fd < 0) {
return -1;
}
return object_fd;
}
}
SymbolizeCallback g_symbolize_callback = NULL;
void InstallSymbolizeCallback(SymbolizeCallback callback) {
g_symbolize_callback = callback;
}
// This function wraps the Demangle function to provide an interface
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int 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.
int len = strlen(demangled);
if (len + 1 <= out_size) { // +1 for '\0'.
SAFE_ASSERT(len < sizeof(demangled));
memmove(out, demangled, len + 1);
}
}
}
// The implementation of our symbolization routine. If it
// successfully finds the symbol containing "pc" and obtains the
// symbol name, returns true and write the symbol name to "out".
// Otherwise, returns false. If Callback function is installed via
// InstallSymbolizeCallback(), the function is also called in this function,
// and "out" is used as its output.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
int out_size) {
uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
uint64_t start_address = 0;
int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
start_address);
if (object_fd == -1) {
return false;
}
FileDescriptor wrapped_object_fd(object_fd);
int elf_type = FileGetElfType(wrapped_object_fd.get());
if (elf_type == -1) {
return false;
}
if (g_symbolize_callback) {
// Run the call back if it's installed.
// Note: relocation (and much of the rest of this code) will be
// wrong for prelinked shared libraries and PIE executables.
uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
pc, out, out_size,
relocation);
if (num_bytes_written > 0) {
out += num_bytes_written;
out_size -= num_bytes_written;
}
}
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
out, out_size, start_address)) {
return false;
}
// Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace(out, out_size);
return true;
}
bool Symbolize(void *pc, char *out, int out_size) {
SAFE_ASSERT(out_size >= 0);
return SymbolizeAndDemangle(pc, out, out_size);
}
_END_GOOGLE_NAMESPACE_
#else /* __ELF__ */
#include <assert.h>
#include "config.h"
_START_GOOGLE_NAMESPACE_
// TODO: osx-port-incomplete. An alternative is Brakepad, but I don't
// think we want that mixed up in google3.
bool Symbolize(void *pc, char *out, int out_size) {
assert(0);
return false;
}
_END_GOOGLE_NAMESPACE_
#endif

79
src/symbolize.h Normal file
View File

@ -0,0 +1,79 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Satoru Takabayashi
//
// This library provides Symbolize() function that symbolizes program
// counters to their corresponding symbol names on linux platforms.
// This library has a minimal implementation of an ELF symbol table
// reader (i.e. it doesn't depend on libelf, etc.).
//
// The algorithm used in Symbolize() is as follows.
//
// 1. Go through a list of maps in /proc/self/maps and find the map
// containing the program counter.
//
// 2. Open the mapped file and find a regular symbol table inside.
// Iterate over symbols in the symbol table and look for the symbol
// containing the program counter. If such a symbol is found,
// obtain the symbol name, and demangle the symbol if possible.
// If the symbol isn't found in the regular symbol table (binary is
// stripped), try the same thing with a dynamic symbol table.
//
// Note that Symbolize() is originally implemented to be used in
// FailureSignalHandler() in base/google.cc. Hence it doesn't use
// malloc() and other unsafe operations. It should be both
// thread-safe and async-signal-safe.
#ifndef BASE_SYMBOLIZE_H_
#define BASE_SYMBOLIZE_H_
#include "config.h"
#include "glog/logging.h"
#if defined(__ELF__) // defined by gcc on Linux
#include <elf.h>
#include <link.h> // For ElfW() macro.
// If there is no ElfW macro, let's define it by ourself.
#ifndef ElfW
# if SIZEOF_VOID_P == 4
# define ElfW(type) Elf32_##type
# elif SIZEOF_VOID_P == 8
# define ElfW(type) Elf64_##type
# else
# error "Unknown sizeof(void *)"
# endif
#endif
_START_GOOGLE_NAMESPACE_
// Installs a callback function, which will be called right before a symbol name
// is printed. The callback is intended to be used for showing a file name and a
// line number preceding a symbol name.
// "fd" is a file descriptor of the object file containing the program
// counter "pc". The callback function should write output to "out"
// and return the size of the output written. On error, the callback
// function should return -1.
typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
uint64 relocation);
void InstallSymbolizeCallback(SymbolizeCallback callback);
// Gets the section header for the given name, if it exists. Returns true on
// success. Otherwise, returns false.
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out);
_END_GOOGLE_NAMESPACE_
#endif /* __ELF__ */
_START_GOOGLE_NAMESPACE_
// Symbolizes a program counter. On success, returns true and write the
// symbol name to "out". The symbol name is demangled if possible
// (supports symbols generated by GCC 3.x or newer). Otherwise,
// returns false.
bool Symbolize(void *pc, char *out, int out_size);
_END_GOOGLE_NAMESPACE_
#endif // BASE_SYMBOLIZE_H_

328
src/symbolize_unittest.cc Normal file
View File

@ -0,0 +1,328 @@
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Satoru Takabayashi
//
// Unit tests for functions in symbolize.cc.
#include <signal.h>
#include <iostream>
#include "glog/logging.h"
#include "symbolize.h"
#include "googletest.h"
#include "config.h"
#include "utilities.h"
using namespace std;
using namespace GOOGLE_NAMESPACE;
#if defined(HAVE_STACKTRACE) && defined(__ELF__)
#define always_inline
// This unit tests make sense only with GCC.
// Uses lots of GCC specific features.
#if defined(__GNUC__) && !defined(__OPENCC__)
# if __GNUC__ >= 4
# define TEST_WITH_MODERN_GCC
# if __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
# undef always_inline
# define always_inline __attribute__((always_inline))
# define HAVE_ALWAYS_INLINE
# endif // __i386__
# else
# endif // __GNUC__ >= 4
# if defined(__i386__) || defined(__x86_64__)
# define TEST_X86_32_AND_64 1
# endif // defined(__i386__) || defined(__x86_64__)
#endif
// A wrapper function for Symbolize() to make the unit test simple.
static const char *TrySymbolize(void *pc) {
static char symbol[4096];
if (Symbolize(pc, symbol, sizeof(symbol))) {
return symbol;
} else {
return NULL;
}
}
// Make them C linkage to avoid mangled names.
extern "C" {
void nonstatic_func() {
volatile int a = 0;
++a;
}
static void static_func() {
volatile int a = 0;
++a;
}
}
TEST(Symbolize, Symbolize) {
// We do C-style cast since GCC 2.95.3 doesn't allow
// reinterpret_cast<void *>(&func).
// Compilers should give us pointers to them.
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
EXPECT_STREQ("static_func", TrySymbolize((void *)(&static_func)));
EXPECT_TRUE(NULL == TrySymbolize(NULL));
}
struct Foo {
static void func(int x);
};
void ATTRIBUTE_NOINLINE Foo::func(int x) {
volatile int a = x;
++a;
}
// With a modern GCC, Symbolize() should return demangled symbol
// names. Function parameters should be omitted.
#ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100);
EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
}
#endif
// Tests that verify that Symbolize footprint is within some limit.
// To measure the stack footprint of the Symbolize function, we create
// a signal handler (for SIGUSR1 say) that calls the Symbolize function
// on an alternate stack. This alternate stack is initialized to some
// known pattern (0x55, 0x55, 0x55, ...). We then self-send this signal,
// and after the signal handler returns, look at the alternate stack
// buffer to see what portion has been touched.
//
// This trick gives us the the stack footprint of the signal handler.
// But the signal handler, even before the call to Symbolize, consumes
// some stack already. We however only want the stack usage of the
// Symbolize function. To measure this accurately, we install two signal
// handlers: one that does nothing and just returns, and another that
// calls Symbolize. The difference between the stack consumption of these
// two signals handlers should give us the Symbolize stack foorprint.
static void *g_pc_to_symbolize;
static char g_symbolize_buffer[4096];
static char *g_symbolize_result;
static void EmptySignalHandler(int signo) {}
static void SymbolizeSignalHandler(int signo) {
if (Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
sizeof(g_symbolize_buffer))) {
g_symbolize_result = g_symbolize_buffer;
} else {
g_symbolize_result = NULL;
}
}
const int kAlternateStackSize = 8096;
const char kAlternateStackFillValue = 0x55;
// These helper functions look at the alternate stack buffer, and figure
// out what portion of this buffer has been touched - this is the stack
// consumption of the signal handler running on this alternate stack.
static bool StackGrowsDown(int *x) {
int y;
return &y < x;
}
static int GetStackConsumption(const char* alt_stack) {
int x;
if (StackGrowsDown(&x)) {
for (int i = 0; i < kAlternateStackSize; i++) {
if (alt_stack[i] != kAlternateStackFillValue) {
return (kAlternateStackSize - i);
}
}
} else {
for (int i = (kAlternateStackSize - 1); i >= 0; i--) {
if (alt_stack[i] != kAlternateStackFillValue) {
return i;
}
}
}
return -1;
}
#ifdef HAVE_SIGALTSTACK
// Call Symbolize and figure out the stack footprint of this call.
static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
g_pc_to_symbolize = pc;
// The alt-signal-stack cannot be heap allocated because there is a
// bug in glibc-2.2 where some signal handler setup code looks at the
// current stack pointer to figure out what thread is currently running.
// Therefore, the alternate stack must be allocated from the main stack
// itself.
char altstack[kAlternateStackSize];
memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
// Set up the alt-signal-stack (and save the older one).
stack_t sigstk = {}; // Zero-clear.
stack_t old_sigstk;
sigstk.ss_sp = altstack;
sigstk.ss_size = kAlternateStackSize;
sigstk.ss_flags = 0;
CHECK_ERR(sigaltstack(&sigstk, &old_sigstk));
// Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
struct sigaction sa = {}; // Zero-clear;
struct sigaction old_sa1, old_sa2;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
// SIGUSR1 maps to EmptySignalHandler.
sa.sa_handler = EmptySignalHandler;
CHECK_ERR(sigaction(SIGUSR1, &sa, &old_sa1));
// SIGUSR2 maps to SymbolizeSignalHanlder.
sa.sa_handler = SymbolizeSignalHandler;
CHECK_ERR(sigaction(SIGUSR2, &sa, &old_sa2));
// Send SIGUSR1 signal and measure the stack consumption of the empty
// signal handler.
CHECK_ERR(kill(getpid(), SIGUSR1));
int stack_consumption1 = GetStackConsumption(altstack);
// Send SIGUSR2 signal and measure the stack consumption of the symbolize
// signal handler.
CHECK_ERR(kill(getpid(), SIGUSR2));
int stack_consumption2 = GetStackConsumption(altstack);
// The difference between the two stack consumption values is the
// stack footprint of the Symbolize function.
if (stack_consumption1 != -1 && stack_consumption2 != -1) {
*stack_consumed = stack_consumption2 - stack_consumption1;
} else {
*stack_consumed = -1;
}
// Log the stack consumption values.
LOG(INFO) << "Stack consumption of empty signal handler: "
<< stack_consumption1;
LOG(INFO) << "Stack consumption of symbolize signal handler: "
<< stack_consumption2;
LOG(INFO) << "Stack consumption of Symbolize: " << *stack_consumed;
// Now restore the old alt-signal-stack and signal handlers.
CHECK_ERR(sigaltstack(&old_sigstk, NULL));
CHECK_ERR(sigaction(SIGUSR1, &old_sa1, NULL));
CHECK_ERR(sigaction(SIGUSR2, &old_sa2, NULL));
return g_symbolize_result;
}
// Symbolize stack consumption should be within 2kB.
const int kStackConsumptionUpperLimit = 2048;
TEST(Symbolize, SymbolizeStackConsumption) {
int stack_consumed;
const char* symbol;
symbol = SymbolizeStackConsumption((void *)(&nonstatic_func),
&stack_consumed);
EXPECT_STREQ("nonstatic_func", symbol);
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
symbol = SymbolizeStackConsumption((void *)(&static_func),
&stack_consumed);
EXPECT_STREQ("static_func", symbol);
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
}
#ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
Foo::func(100);
int stack_consumed;
const char* symbol;
symbol = SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed);
EXPECT_STREQ("Foo::func()", symbol);
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
}
#endif
#endif // HAVE_SIGALTSTACK
// x86 specific tests. Uses some inline assembler.
extern "C" {
inline void* always_inline inline_func() {
register void *pc = NULL;
#ifdef TEST_X86_32_AND_64
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
#endif
return pc;
}
void* ATTRIBUTE_NOINLINE non_inline_func() {
register void *pc = NULL;
#ifdef TEST_X86_32_AND_64
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
#endif
return pc;
}
void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
#if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
void *pc = non_inline_func();
const char *symbol = TrySymbolize(pc);
CHECK(symbol != NULL);
CHECK_EQ(0, strcmp(symbol, "non_inline_func"));
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
#endif
}
void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
#if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
void *pc = inline_func(); // Must be inlined.
const char *symbol = TrySymbolize(pc);
CHECK(symbol != NULL);
CHECK_EQ(0, strcmp(symbol, __FUNCTION__));
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
#endif
}
}
// Test with a return address.
void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
#if defined(HAVE_ATTRIBUTE_NOINLINE)
void *return_address = __builtin_return_address(0);
const char *symbol = TrySymbolize(return_address);
CHECK(symbol != NULL);
CHECK_EQ(0, strcmp(symbol, "main"));
cout << "Test case TestWithReturnAddress passed." << endl;
#endif
}
int main(int argc, char **argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
// Symbolize() now only supports ELF binaries.
// The test makes sense only if __ELF__ is defined.
#ifndef __ELF__
return 0;
#else
TestWithPCInsideInlineFunction();
TestWithPCInsideNonInlineFunction();
TestWithReturnAddress();
return RUN_ALL_TESTS();
#endif
}
#else
int main() {
printf("PASS (no symbolize support)\n");
return 0;
}
#endif // HAVE_STACKTRACE

172
src/utilities.cc Normal file
View File

@ -0,0 +1,172 @@
#include "utilities.h"
#include <sys/time.h>
#include <time.h>
#include "base/googleinit.h"
#include "stacktrace.h"
#include "symbolize.h"
using std::string;
_START_GOOGLE_NAMESPACE_
static const char* g_program_invocation_short_name = NULL;
static pthread_t g_main_thread_id;
// The following APIs are all internal.
#ifdef HAVE_STACKTRACE
#include "stacktrace.h"
#include "symbolize.h"
#include "base/commandlineflags.h"
DEFINE_bool(symbolize_stacktrace, true,
"Symbolize the stack trace in the tombstone");
typedef void DebugWriter(const char*, void*);
// The %p field width for printf() functions is two characters per byte.
// For some environments, add two extra bytes for the leading "0x".
static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
static void DebugWriteToStderr(const char* data, void *unused) {
// This one is signal-safe.
write(STDERR_FILENO, data, strlen(data));
}
// Print a program counter and its symbol name.
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
char tmp[1024];
const char *symbol = "(unknown)";
// Symbolizes the previous address of pc because pc may be in the
// next function. The overrun happens when the function ends with
// a call to a function annotated noreturn (e.g. CHECK).
if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
symbol = tmp;
}
char buf[1024];
snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
prefix, kPrintfPointerFieldWidth, pc, symbol);
writerfn(buf, arg);
}
// Print a program counter and the corresponding stack frame size.
static void DumpPCAndFrameSize(DebugWriter *writerfn, void *arg, void *pc,
int framesize, const char * const prefix) {
char buf[100];
if (framesize <= 0) {
snprintf(buf, sizeof(buf), "%s@ %*p (unknown)\n",
prefix, kPrintfPointerFieldWidth, pc);
} else {
snprintf(buf, sizeof(buf), "%s@ %*p %9d\n",
prefix, kPrintfPointerFieldWidth, pc, framesize);
}
writerfn(buf, arg);
}
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
char buf[100];
snprintf(buf, sizeof(buf), "%s@ %*p\n",
prefix, kPrintfPointerFieldWidth, pc);
writerfn(buf, arg);
}
// Dump current stack trace as directed by writerfn
static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
// Print stack trace
void* stack[32];
int depth = GetStackTrace(stack, sizeof(stack)/sizeof(*stack), skip_count+1);
for (int i = 0; i < depth; i++) {
#if defined(__ELF__)
if (FLAGS_symbolize_stacktrace) {
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
} else {
DumpPC(writerfn, arg, stack[i], " ");
}
#else
DumpPC(writerfn, arg, stack[i], " ");
#endif
}
}
static void DumpStackTraceAndExit() {
DumpStackTrace(1, DebugWriteToStderr, NULL);
exit(1);
}
#endif
namespace glog_internal_namespace_ {
const char* ProgramInvocationShortName() {
if (g_program_invocation_short_name != NULL) {
return g_program_invocation_short_name;
} else {
// TODO(hamaji): Use /proc/self/cmdline and so?
return "UNKNOWN";
}
}
bool IsGoogleLoggingInitialized() {
return g_program_invocation_short_name != NULL;
}
bool is_default_thread() {
if (g_program_invocation_short_name == NULL) {
// InitGoogleLogging() not yet called, so unlikely to be in a different
// thread
return true;
} else {
return pthread_equal(pthread_self(), g_main_thread_id);
}
}
int64 CycleClock_Now() {
// TODO(hamaji): temporary impementation - it might be too slow.
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
}
int64 UsecToCycles(int64 usec) {
return usec;
}
static int32 g_main_thread_pid = getpid();
int32 GetMainThreadPid() {
return g_main_thread_pid;
}
static string g_my_user_name;
const string& MyUserName() {
return g_my_user_name;
}
static void MyUserNameInitializer() {
// TODO(hamaji): Probably this is not portable.
const char* user = getenv("USER");
if (user != NULL) {
g_my_user_name = user;
} else {
g_my_user_name = "invalid-user";
}
}
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
} // namespace glog_internal_namespace_
void InitGoogleLogging(const char* argv0) {
const char* slash = strrchr(argv0, '/');
#ifdef OS_WINDOWS
if (!slash) slash = strrchr(argv0, '\\');
#endif
g_program_invocation_short_name = slash ? slash + 1 : argv0;
g_main_thread_id = pthread_self();
#ifdef HAVE_STACKTRACE
InstallFailureFunction(&DumpStackTraceAndExit);
#endif
}
_END_GOOGLE_NAMESPACE_

79
src/utilities.h Normal file
View File

@ -0,0 +1,79 @@
// Define utilties for glog internal usage.
#ifndef UTILITIES_H__
#define UTILITIES_H__
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
# define OS_WINDOWS
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define OS_LINUX
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define OS_MACOSX
#elif defined(__FreeBSD__)
# define OS_FREEBSD
#else
// TODO(hamaji): Add other platforms.
#endif
// printf macros for size_t, in the style of inttypes.h
#ifdef _LP64
#define __PRIS_PREFIX "z"
#else
#define __PRIS_PREFIX
#endif
// Use these macros after a % in a printf format string
// to get correct 32/64 bit behavior, like this:
// size_t size = records.size();
// printf("%"PRIuS"\n", size);
#define PRIdS __PRIS_PREFIX "d"
#define PRIxS __PRIS_PREFIX "x"
#define PRIuS __PRIS_PREFIX "u"
#define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o"
#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
#include <string>
#include "config.h"
#include "glog/logging.h"
#if defined(HAVE_EXECINFO_H)
# define HAVE_STACKTRACE
#elif defined(STACKTRACE_WITH_FRAME_POINTER)
# define HAVE_STACKTRACE
#endif
_START_GOOGLE_NAMESPACE_
namespace glog_internal_namespace_ {
#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define HAVE_ATTRIBUTE_NOINLINE
#else
# define ATTRIBUTE_NOINLINE
#endif
const char* ProgramInvocationShortName();
bool IsGoogleLoggingInitialized();
bool is_default_thread();
int64 CycleClock_Now();
int64 UsecToCycles(int64 usec);
int32 GetMainThreadPid();
const std::string& MyUserName();
}
_END_GOOGLE_NAMESPACE_
using namespace GOOGLE_NAMESPACE::glog_internal_namespace_;
#endif // UTILITIES_H__

218
src/vlog_is_on.cc Normal file
View File

@ -0,0 +1,218 @@
// Copyright 1999, 2007 Google Inc. All Rights Reserved.
// Author: Ray Sidney and many others
// Broken out from logging.cc by Soren Lassen
// logging_unittest.cc covers the functionality herein
#include "utilities.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fnmatch.h> // fnmatch() is used in obsolete _InitVLOG
#include <cstdio>
#include <string>
#include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "base/googleinit.h"
// glog doesn't have annotation
#define ANNOTATE_BENIGN_RACE(address, description)
using std::string;
DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
" Overridable by --vmodule.");
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.");
_START_GOOGLE_NAMESPACE_
// Implementation of fnmatch that does not need 0-termination
// of arguments and does not allocate any memory,
// but we only support "*" and "?" wildcards, not the "[...]" patterns.
// It's not a static function for the unittest.
bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len) {
int p = 0;
int s = 0;
while (1) {
if (p == patt_len && s == str_len) return true;
if (p == patt_len) return false;
if (s == str_len) return p+1 == patt_len && pattern[p] == '*';
if (pattern[p] == str[s] || pattern[p] == '?') {
p += 1;
s += 1;
continue;
}
if (pattern[p] == '*') {
if (p+1 == patt_len) return true;
do {
if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
return true;
}
s += 1;
} while (s != str_len);
return false;
}
return false;
}
}
int32 kLogSiteUninitialized = 1000;
// List of per-module log levels from FLAGS_vmodule.
// Once created each element is never deleted/modified
// except for the vlog_level: other threads will read VModuleInfo blobs
// w/o locks and we'll store pointers to vlog_level at VLOG locations
// that will never go away.
// We can't use an STL struct here as we wouldn't know
// when it's safe to delete/update it: other threads need to use it w/o locks.
struct VModuleInfo {
string module_pattern;
mutable int32 vlog_level; // Conceptually this is an AtomicWord, but it's
// too much work to use AtomicWord type here
// w/o much actual benefit.
const VModuleInfo* next;
};
// This protects the following global variables.
static Mutex vmodule_lock;
// Pointer to head of the VModuleInfo list.
// It's a map from module pattern to logging level for those module(s).
static VModuleInfo* vmodule_list = 0;
// Boolean initialization flag.
static bool inited_vmodule = false;
static void VLOG2Initializer() {
MutexLock l(&vmodule_lock);
// Can now parse --vmodule flag and initialize mapping of module-specific
// logging levels.
inited_vmodule = false;
const char* vmodule = FLAGS_vmodule.c_str();
const char* sep;
VModuleInfo* head = NULL;
VModuleInfo* tail = NULL;
while ((sep = strchr(vmodule, '=')) != NULL) {
string pattern(vmodule, sep - vmodule);
int module_level;
if (sscanf(sep, "=%d", &module_level) == 1) {
VModuleInfo* info = new VModuleInfo;
info->module_pattern = pattern;
info->vlog_level = module_level;
if (head) tail->next = info;
else head = info;
tail = info;
}
// Skip past this entry
vmodule = strchr(sep, ',');
if (vmodule == NULL) break;
vmodule++; // Skip past ","
}
if (head) { // Put them into the list at the head:
tail->next = vmodule_list;
vmodule_list = head;
}
inited_vmodule = true;
}
REGISTER_MODULE_INITIALIZER(vlog_is_on, VLOG2Initializer());
// This can be called very early, so we use SpinLock and RAW_VLOG here.
int SetVLOGLevel(const char* module_pattern, int log_level) {
int result = FLAGS_v;
int const pattern_len = strlen(module_pattern);
bool found = false;
MutexLock l(&vmodule_lock); // protect whole read-modify-write
for (const VModuleInfo* info = vmodule_list;
info != NULL; info = info->next) {
if (info->module_pattern == module_pattern) {
if (!found) {
result = info->vlog_level;
found = true;
}
info->vlog_level = log_level;
} else if (!found &&
SafeFNMatch_(info->module_pattern.c_str(),
info->module_pattern.size(),
module_pattern, pattern_len)) {
result = info->vlog_level;
found = true;
}
}
if (!found) {
VModuleInfo* info = new VModuleInfo;
info->module_pattern = module_pattern;
info->vlog_level = log_level;
info->next = vmodule_list;
vmodule_list = info;
}
RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
return result;
}
// NOTE: Individual VLOG statements cache the integer log level pointers.
// NOTE: This function must not allocate memory or require any locks.
bool InitVLOG3__(int32** site_flag, int32* site_default,
const char* fname, int32 verbose_level) {
MutexLock l(&vmodule_lock);
bool read_vmodule_flag = inited_vmodule;
if (!read_vmodule_flag && vmodule_list == 0) {
// The command line --vmodule flags haven't been parsed
// and nothing was set with SetVLOGLevel yet,
// but *site_default (usually FLAGS_v) might be manually set
// by some early-executing code, or else it's still 0.
return *site_default >= verbose_level;
}
// protect the errno global in case someone writes:
// VLOG(..) << "The last error was " << strerror(errno)
int old_errno = errno;
// site_default normally points to FLAGS_v
int32* site_flag_value = site_default;
// Get basename for file
const char* base = strrchr(fname, '/');
base = base ? (base+1) : fname;
const char* base_end = strchr(base, '.');
size_t base_length = base_end ? (base_end - base) : strlen(base);
// Trim out trailing "-inl" if any
if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
base_length -= 4;
}
// TODO: Trim out _unittest suffix? Perhaps it is better to have
// the extra control and just leave it there.
// find target in vector of modules, replace site_flag_value with
// a module-specific verbose level, if any.
for (const VModuleInfo* info = vmodule_list;
info != NULL; info = info->next) {
if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
base, base_length)) {
site_flag_value = &info->vlog_level;
// value at info->vlog_level is now what controls
// the VLOG at the caller site forever
break;
}
}
// Cache the vlog value pointer if --vmodule flag has been parsed.
ANNOTATE_BENIGN_RACE(site_flag,
"*site_flag may be written by several threads,"
" but the value will be the same");
if (read_vmodule_flag) *site_flag = site_flag_value;
// restore the errno in case something recoverable went wrong during
// the initialization of the VLOG mechanism (see above note "protect the..")
errno = old_errno;
return *site_flag_value >= verbose_level;
}
_END_GOOGLE_NAMESPACE_