glog 0.1
git-svn-id: https://google-glog.googlecode.com/svn/trunk@2 eb4d4688-79bd-11dd-afb4-1d65580434c0
This commit is contained in:
parent
1c5d6dc798
commit
b8b4db46fe
28
COPYING
Normal file
28
COPYING
Normal 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
6
ChangeLog
Normal 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
230
INSTALL
Normal 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
172
Makefile.am
Normal 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
1185
Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
5
README
Normal file
5
README
Normal 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
7274
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
25
autogen.sh
Executable file
25
autogen.sh
Executable 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
99
compile
Executable 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
1466
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1579
config.sub
vendored
Executable file
1579
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
120
configure.ac
Normal file
120
configure.ac
Normal 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
530
depcomp
Executable 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
115
doc/designstyle.css
Normal 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
506
doc/glog.html
Normal 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(<a
|
||||
particular <a href="#severity">severity level</a>>), e.g.
|
||||
|
||||
<pre>
|
||||
#include <google/logging.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Initialize Google's logging library.
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
// ...
|
||||
LOG(INFO) << "Found " << num_cookies << " 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/<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>"
|
||||
(e.g., "/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474").
|
||||
By default, glog copies the log messages of severity level
|
||||
<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 <module name>=<log level>.
|
||||
<module name>
|
||||
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).
|
||||
<log level> 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) << "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) << "Got the " << COUNTER << "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) << "Got the " << COUNTER
|
||||
<< "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) << "Got the " << COUNTER << "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) << "Found cookies";
|
||||
|
||||
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
|
||||
|
||||
DLOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "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) << "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<<(ostream,
|
||||
...)</code> defined.
|
||||
|
||||
<p>You may append to the error message like so:
|
||||
|
||||
<pre>
|
||||
CHECK_NE(1, 2) << ": 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) << "I'm printed when you run the program with --v=1 or higher";
|
||||
VLOG(2) << "I'm printed when you run the program with --v=2 or higher";
|
||||
</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) << ...;
|
||||
}
|
||||
</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))
|
||||
<< "I'm printed when size is more than 1024 and when you run the "
|
||||
"program with --v=1 or more";
|
||||
VLOG_EVERY_N(1, 10)
|
||||
<< "I'm printed every 10th occurrence, and when you run the program "
|
||||
"with --v=1 or more. Present occurence is " << COUNTER;
|
||||
VLOG_IF_EVERY_N(1, (size > 1024), 10)
|
||||
<< "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 " << 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(&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><google/raw_logging.h></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 <google/logging.h>
|
||||
</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
323
install-sh
Executable 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:
|
||||
16
m4/ac_have_attribute.m4
Normal file
16
m4/ac_have_attribute.m4
Normal 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__)
|
||||
])
|
||||
14
m4/ac_have_builtin_expect.m4
Normal file
14
m4/ac_have_builtin_expect.m4
Normal 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
31
m4/ac_rwlock.m4
Normal 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
353
m4/acx_pthread.m4
Normal 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
36
m4/google_namespace.m4
Normal 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
15
m4/namespaces.m4
Normal 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
25
m4/stl_namespace.m4
Normal 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
15
m4/using_operator.m4
Normal 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
360
missing
Executable 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
158
mkinstalldirs
Executable 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
70
packages/deb.sh
Executable 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
7
packages/deb/README
Normal 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
5
packages/deb/changelog
Normal 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
1
packages/deb/compat
Normal file
@ -0,0 +1 @@
|
||||
4
|
||||
23
packages/deb/control
Normal file
23
packages/deb/control
Normal 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
35
packages/deb/copyright
Normal 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
8
packages/deb/docs
Normal file
@ -0,0 +1,8 @@
|
||||
AUTHORS
|
||||
COPYING
|
||||
ChangeLog
|
||||
INSTALL
|
||||
NEWS
|
||||
README
|
||||
doc/designstyle.css
|
||||
doc/glog.html
|
||||
3
packages/deb/libgoogle-glog-dev.dirs
Normal file
3
packages/deb/libgoogle-glog-dev.dirs
Normal file
@ -0,0 +1,3 @@
|
||||
usr/lib
|
||||
usr/include
|
||||
usr/include/glog
|
||||
8
packages/deb/libgoogle-glog-dev.install
Normal file
8
packages/deb/libgoogle-glog-dev.install
Normal 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
|
||||
1
packages/deb/libgoogle-glog0.dirs
Normal file
1
packages/deb/libgoogle-glog0.dirs
Normal file
@ -0,0 +1 @@
|
||||
usr/lib
|
||||
2
packages/deb/libgoogle-glog0.install
Normal file
2
packages/deb/libgoogle-glog0.install
Normal file
@ -0,0 +1,2 @@
|
||||
usr/lib/lib*.so.*
|
||||
debian/tmp/usr/lib/lib*.so.*
|
||||
117
packages/deb/rules
Executable file
117
packages/deb/rules
Executable 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
75
packages/rpm.sh
Executable 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
71
packages/rpm/rpm.spec
Normal 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
117
src/base/commandlineflags.h
Normal 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
51
src/base/googleinit.h
Normal 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
252
src/base/mutex.h
Normal 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
104
src/config.h.in
Normal 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
1203
src/demangle.cc
Normal file
File diff suppressed because it is too large
Load Diff
56
src/demangle.h
Normal file
56
src/demangle.h
Normal 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
83
src/demangle_unittest.cc
Normal 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
63
src/demangle_unittest.sh
Executable 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
137
src/demangle_unittest.txt
Normal 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
48
src/glog/log_severity.h
Normal 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
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
87
src/glog/raw_logging.h.in
Normal 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
128
src/glog/stl_logging.h.in
Normal 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
89
src/glog/vlog_is_on.h.in
Normal 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
483
src/googletest.h
Normal 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
1592
src/logging.cc
Normal file
File diff suppressed because it is too large
Load Diff
45
src/logging_striplog_test.sh
Executable file
45
src/logging_striplog_test.sh
Executable 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"
|
||||
7
src/logging_striptest10.cc
Normal file
7
src/logging_striptest10.cc
Normal 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"
|
||||
7
src/logging_striptest2.cc
Normal file
7
src/logging_striptest2.cc
Normal 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"
|
||||
40
src/logging_striptest_main.cc
Normal file
40
src/logging_striptest_main.cc
Normal 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
923
src/logging_unittest.cc
Normal 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
293
src/logging_unittest.err
Normal 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
114
src/raw_logging.cc
Normal 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
68
src/stacktrace.cc
Normal 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
68
src/stacktrace.h
Normal 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_
|
||||
119
src/stacktrace_framesizes_unittest.cc
Normal file
119
src/stacktrace_framesizes_unittest.cc
Normal 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
|
||||
81
src/stacktrace_generic-inl.h
Normal file
81
src/stacktrace_generic-inl.h
Normal 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_
|
||||
127
src/stacktrace_libunwind-inl.h
Normal file
127
src/stacktrace_libunwind-inl.h
Normal 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_
|
||||
182
src/stacktrace_powerpc-inl.h
Normal file
182
src/stacktrace_powerpc-inl.h
Normal 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
124
src/stacktrace_unittest.cc
Normal 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
197
src/stacktrace_x86-inl.h
Normal 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
127
src/stacktrace_x86_64-inl.h
Normal 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
164
src/stl_logging_unittest.cc
Normal 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
613
src/symbolize.cc
Normal 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
79
src/symbolize.h
Normal 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
328
src/symbolize_unittest.cc
Normal 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
172
src/utilities.cc
Normal 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
79
src/utilities.h
Normal 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
218
src/vlog_is_on.cc
Normal 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_
|
||||
Loading…
Reference in New Issue
Block a user