mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-14 17:49:57 +08:00
abi.html: New.
2004-05-13 Benjamin Kosnik <bkoz@redhat.com> * docs/html/abi.html: New. * docs/html/abi.txt: Remove. * docs/html/documentation.html: Add link. * testsuite/Makefile.am: Add files. * testsuite/Makefile.in: Regenerated. * testsuite/abi_check.cc: Move and modify code into... * testsuite/testsuite_abi.cc: Add. * testsuite/testsuite_abi.h: Add. * docs/html/17_intro/TODO: Update. * include/bits/stl_pair.h: Format. From-SVN: r81781
This commit is contained in:
parent
f8f456c68a
commit
4b260c2013
@ -1,3 +1,17 @@
|
||||
2004-05-13 Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
* docs/html/abi.html: New.
|
||||
* docs/html/abi.txt: Remove.
|
||||
* docs/html/documentation.html: Add link.
|
||||
* testsuite/Makefile.am: Add files.
|
||||
* testsuite/Makefile.in: Regenerated.
|
||||
* testsuite/abi_check.cc: Move and modify code into...
|
||||
* testsuite/testsuite_abi.cc: Add.
|
||||
* testsuite/testsuite_abi.h: Add.
|
||||
|
||||
* docs/html/17_intro/TODO: Update.
|
||||
* include/bits/stl_pair.h: Format.
|
||||
|
||||
2004-05-06 Matthias Klose <doko@debian.org>
|
||||
|
||||
* include/backward/iterator.h: Add GPL copyright info,
|
||||
|
@ -2,16 +2,13 @@ std::allocator
|
||||
|
||||
- switch to mt_allocator with --enable-threads=posix.
|
||||
|
||||
- Try to figure out a way to switch allocators in a more elegant
|
||||
manner, and make the default allocator configurable.
|
||||
|
||||
- persistent allocator
|
||||
|
||||
- global/extern allocator
|
||||
|
||||
std::string
|
||||
|
||||
- re-design for multi-paradigm, meta string class solution incorporating COW
|
||||
- Policy-based design incorporating COW
|
||||
vs. deep copy issues, MT scalability
|
||||
See Andrei Alexandrescu, June 2001, C/C++ Users Journal
|
||||
"Generic<Programming>: A Policy-Based basic_string Implementation"
|
||||
@ -53,8 +50,6 @@ std::locale
|
||||
|
||||
- minimize ctype convertion in data facets, see numpunct/num_put/num_get
|
||||
|
||||
- finish caching data facets and using the caches
|
||||
|
||||
std::basic_filebuf, 27_io
|
||||
|
||||
- wfilebuf, get variable-encoding working and tested, including
|
||||
@ -86,11 +81,11 @@ testsuite
|
||||
|
||||
- diffing generated output files
|
||||
|
||||
- provide testsuites for numerics.
|
||||
|
||||
- make check-abi needs to have full symbol checking. Scope the LSB
|
||||
testsuite, see what's going on with the typeinfo etc. bits.
|
||||
|
||||
- provide testsuites for numerics.
|
||||
|
||||
- try to do a better job of ABI testing, with instantiations of all
|
||||
standard-specified types checked, not just exported symbols.
|
||||
|
||||
@ -140,9 +135,6 @@ Nathan's commentary on cantrip, http://www.cantrip.org/cheaders.html
|
||||
- auto_ptr: seems to be some disagreement on what is
|
||||
standards-conformant behavior, specially on conversion operators.
|
||||
|
||||
- looks like deque::get_allocator not standards conformant or deque
|
||||
allocator non-standard.
|
||||
|
||||
- list::assignment operator needs const_cast
|
||||
|
||||
- a cleaner division between pointers-to-value_type and true iterators
|
||||
|
857
libstdc++-v3/docs/html/abi.html
Normal file
857
libstdc++-v3/docs/html/abi.html
Normal file
@ -0,0 +1,857 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta name="AUTHOR" content="bkoz@gcc.gnu.org (Benjamin Kosnik)" />
|
||||
<meta name="KEYWORDS" content="C++, libstdc++, dynamic, shared, library, ABI, version" />
|
||||
<meta name="DESCRIPTION" content="C++ Standard Library ABI" />
|
||||
<meta name="GENERATOR" content="emacs and ten fingers" />
|
||||
<title>Standard C++ Library ABI</title>
|
||||
<link rel="StyleSheet" href="lib3styles.css" type="text/css" />
|
||||
<link rel="Start" href="documentation.html" type="text/html"
|
||||
title="GNU C++ Standard Library" />
|
||||
<link rel="Copyright" href="17_intro/license.html" type="text/html" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1 class="centered"><a name="top">C++ Standard Library ABI</a></h1>
|
||||
|
||||
<p class="fineprint"><em>
|
||||
The latest version of this document is always available at
|
||||
<a href="http://gcc.gnu.org/onlinedocs/libstdc++/abi.html">
|
||||
http://gcc.gnu.org/onlinedocs/libstdc++/abi.html</a>.
|
||||
</em></p>
|
||||
|
||||
<p><em>
|
||||
To the <a href="http://gcc.gnu.org/libstdc++/">libstdc++-v3 homepage</a>.
|
||||
</em></p>
|
||||
|
||||
<!-- ####################################################### -->
|
||||
<hr />
|
||||
<h3 class="left">
|
||||
<a name="C++interface">The C++ interface</a>
|
||||
</h3>
|
||||
|
||||
<p> C++ applications often dependent on specific language support
|
||||
routines, say for throwing exceptions, or catching exceptions, and
|
||||
perhaps also dependent on features in the C++ Standard Library.
|
||||
</p>
|
||||
|
||||
<p> The C++ Standard Library has many include files, types defined in
|
||||
those include files, specific named functions, and other behavior. The
|
||||
text of these behaviors, as written in source include files, is called
|
||||
the Application Programing Interface, or API.
|
||||
</p>
|
||||
|
||||
<p> Furthermore, C++ source that is compiled into object files is
|
||||
transformed by the compiler: it arranges objects with specific
|
||||
alignment and in a particular layout, mangling names according to a
|
||||
well-defined algorithm, has specific arrangements for the support of
|
||||
virtual functions, etc. These details are defined as the compiler
|
||||
Application Binary Interface, or ABI. The GNU C++ compiler uses an
|
||||
industry-standard C++ ABI starting with version 3. Details can be
|
||||
found in the <a href="http://www.codesourcery.com/cxx-abi/abi.html">
|
||||
ABI specification</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The GNU C++ compiler, g++, has a compiler command line option to
|
||||
switch between various different C++ ABIs. This explicit version
|
||||
switch is the flag <code> -fabi-version</code>. In addition, some
|
||||
g++ command line options may change the ABI as a side-effect of
|
||||
use. Such flags include <code>-fpack-struct</code> and
|
||||
<code>-fno-exceptions</code>, but include others: see the complete
|
||||
list in the GCC manual under the heading <a
|
||||
href="http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code%20Gen%20Options">Options
|
||||
for Code Generation Conventions</a>.
|
||||
</p>
|
||||
|
||||
<p> The configure options used when building a specific libstdc++
|
||||
version may also impact the resulting library ABI. The available
|
||||
configure options, and their impact on the library ABI, are documented
|
||||
<a href="http://gcc.gnu.org/onlinedocs/libstdc++/configopts.html">
|
||||
here</a>.
|
||||
</p>
|
||||
|
||||
<p> Putting all of these ideas together results in the C++ Standard
|
||||
library ABI, which is the compilation of a given library API by a
|
||||
given compiler ABI. In a nutshell:
|
||||
</p>
|
||||
|
||||
<code> library API + compiler ABI = library ABI</code>
|
||||
|
||||
<p>
|
||||
The library ABI is mostly of interest for end-users who have
|
||||
unresolved symbols and are linking dynamically to the C++ Standard
|
||||
library, and who thus must be careful to compile their application
|
||||
with a compiler that is compatible with the available C++ Standard
|
||||
library binary. In this case, compatible is defined with the equation
|
||||
above: given an application compiled with a given compiler ABI and
|
||||
library API, it will work correctly with a Standard C++ Library
|
||||
created with the same constraints.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use a specific version of the C++ ABI, one must use a
|
||||
corresponding GNU C++ toolchain (Ie, g++ and libstdc++) that
|
||||
implements the C++ ABI in question.
|
||||
</p>
|
||||
|
||||
<h3 class="left">
|
||||
<a name="ABI versioning">Versioning</a>
|
||||
</h3>
|
||||
|
||||
<p> The C++ interface has evolved throughout the history of the GNU
|
||||
C++ toolchain. With each release, various details have been changed so
|
||||
as to give distinct versions to the C++ interface.
|
||||
</p>
|
||||
|
||||
<h5 class="left">
|
||||
<a name="goals">Goals of versioning</a>
|
||||
</h5>
|
||||
|
||||
<p>Extending existing, stable ABIs. Versioning gives subsequent stable
|
||||
releases series libraries the ability to add new symbols and add
|
||||
functionality, all the while retaining backwards compatibility with
|
||||
the previous releases in the series. Note: the reverse is not true. It
|
||||
is not possible to take binaries linked with the latest version of a
|
||||
release series (if symbols have been added) and expect the initial
|
||||
release of the series to remain link compatible.
|
||||
</p>
|
||||
|
||||
<p>Allows multiple, incompatible ABIs to coexist at the same time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<h5 class="left">
|
||||
<a name="details"> Version History </a>
|
||||
</h5>
|
||||
<p>
|
||||
How can this complexity be managed? What does C++ versioning mean?
|
||||
Because library and compiler changes often make binaries compiled
|
||||
with one version of the GNU tools incompatible with binaries
|
||||
compiled with other (either newer or older) versions of the same GNU
|
||||
tools, specific techniques are used to make managing this complexity
|
||||
easier.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following techniques are used:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p>Release versioning on the libgcc_s.so binary. This is
|
||||
implemented via file names and the ELF DT_SONAME mechanism (at least
|
||||
on ELF systems).</p>
|
||||
|
||||
<p>It is versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: libgcc_s.so.1</li>
|
||||
<li>gcc-3.0.1: libgcc_s.so.1</li>
|
||||
<li>gcc-3.0.2: libgcc_s.so.1</li>
|
||||
<li>gcc-3.0.3: libgcc_s.so.1</li>
|
||||
<li>gcc-3.0.4: libgcc_s.so.1</li>
|
||||
<li>gcc-3.1.0: libgcc_s.so.1</li>
|
||||
<li>gcc-3.1.1: libgcc_s.so.1</li>
|
||||
<li>gcc-3.2.0: libgcc_s.so.1</li>
|
||||
<li>gcc-3.2.1: libgcc_s.so.1</li>
|
||||
<li>gcc-3.2.2: libgcc_s.so.1</li>
|
||||
<li>gcc-3.2.3: libgcc_s.so.1</li>
|
||||
<li>gcc-3.3.0: libgcc_s.so.1</li>
|
||||
<li>gcc-3.3.1: libgcc_s.so.1</li>
|
||||
<li>gcc-3.3.2: libgcc_s.so.1</li>
|
||||
<li>gcc-3.3.3: libgcc_s.so.1</li>
|
||||
<li>gcc-3.4.0: libgcc_s.so.1</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>Release versioning on the libstdc++.so binary, implemented in the same was as the libgcc_s.so binary, above.
|
||||
|
||||
<p>It is versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: libstdc++.so.3.0.0</li>
|
||||
<li>gcc-3.0.1: libstdc++.so.3.0.1</li>
|
||||
<li>gcc-3.0.2: libstdc++.so.3.0.2</li>
|
||||
<li>gcc-3.0.3: libstdc++.so.3.0.2 (Error should be libstdc++.so.3.0.3)</li>
|
||||
<li>gcc-3.0.4: libstdc++.so.3.0.4</li>
|
||||
<li>gcc-3.1.0: libstdc++.so.4.0.0</li>
|
||||
<li>gcc-3.1.1: libstdc++.so.4.0.1</li>
|
||||
<li>gcc-3.2.0: libstdc++.so.5.0.0</li>
|
||||
<li>gcc-3.2.1: libstdc++.so.5.0.1</li>
|
||||
<li>gcc-3.2.2: libstdc++.so.5.0.2</li>
|
||||
<li>gcc-3.2.3: libstdc++.so.5.0.3 (Not strictly required)</li>
|
||||
<li>gcc-3.3.0: libstdc++.so.5.0.4</li>
|
||||
<li>gcc-3.3.1: libstdc++.so.5.0.5</li>
|
||||
<li>gcc-3.3.2: libstdc++.so.5.0.5</li>
|
||||
<li>gcc-3.3.3: libstdc++.so.5.0.5</li>
|
||||
<li>gcc-3.4.0: libstdc++.so.6.0.0</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>Symbol versioning on the libgcc_s.so binary.
|
||||
<p>mapfile: gcc/libgcc-std.ver</p>
|
||||
|
||||
<p>It is versioned with the following labels and version definitions:</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: GCC_3.0</li>
|
||||
<li>gcc-3.0.1: GCC_3.0</li>
|
||||
<li>gcc-3.0.2: GCC_3.0</li>
|
||||
<li>gcc-3.0.3: GCC_3.0</li>
|
||||
<li>gcc-3.0.4: GCC_3.0</li>
|
||||
<li>gcc-3.1.0: GCC_3.0</li>
|
||||
<li>gcc-3.1.1: GCC_3.0</li>
|
||||
<li>gcc-3.2.0: GCC_3.0</li>
|
||||
<li>gcc-3.2.1: GCC_3.0</li>
|
||||
<li>gcc-3.2.2: GCC_3.0</li>
|
||||
<li>gcc-3.2.3: GCC_3.0</li>
|
||||
<li>gcc-3.3.0: GCC_3.0</li>
|
||||
<li>gcc-3.3.1: GCC_3.0</li>
|
||||
<li>gcc-3.3.2: GCC_3.0</li>
|
||||
<li>gcc-3.3.3: GCC_3.0</li>
|
||||
<li>gcc-3.4.0: GCC_3.0</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>Symbol versioning on the libstdc++.so binary.
|
||||
|
||||
<p>mapfile: libstdc++-v3/config/linker-map.gnu</p>
|
||||
<p>It is versioned with the following labels and version
|
||||
definitions, where the version definition is the maximum for a
|
||||
particular release. Note, only symbol which are newly introduced
|
||||
will use the maximum version definition. Thus, for release series
|
||||
with the same label, but incremented version definitions, the later
|
||||
release has both versions. (An example of this would be the
|
||||
gcc-3.2.1 release, which has GLIBCPP_3.2.1 for new symbols and
|
||||
GLIBCPP_3.2 for symbols that were introduced in the gcc-3.2.0
|
||||
release.)
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: (Error, not versioned)</li>
|
||||
<li>gcc-3.0.1: (Error, not versioned)</li>
|
||||
<li>gcc-3.0.2: (Error, not versioned)</li>
|
||||
<li>gcc-3.0.3: (Error, not versioned)</li>
|
||||
<li>gcc-3.0.4: (Error, not versioned)</li>
|
||||
<li>gcc-3.1.0: GLIBCPP_3.1, CXXABI_1</li>
|
||||
<li>gcc-3.1.1: GLIBCPP_3.1, CXXABI_1</li>
|
||||
<li>gcc-3.2.0: GLIBCPP_3.2, CXXABI_1.2</li>
|
||||
<li>gcc-3.2.1: GLIBCPP_3.2.1, CXXABI_1.2</li>
|
||||
<li>gcc-3.2.2: GLIBCPP_3.2.2, CXXABI_1.2</li>
|
||||
<li>gcc-3.2.3: GLIBCPP_3.2.2, CXXABI_1.2</li>
|
||||
<li>gcc-3.3.0: GLIBCPP_3.2.2, CXXABI_1.2.1</li>
|
||||
<li>gcc-3.3.1: GLIBCPP_3.2.3, CXXABI_1.2.1</li>
|
||||
<li>gcc-3.3.2: GLIBCPP_3.2.3, CXXABI_1.2.1</li>
|
||||
<li>gcc-3.3.3: GLIBCPP_3.2.3, CXXABI_1.2.1</li>
|
||||
<li>gcc-3.4.0: GLIBCXX_3.4, CXXABI_1.3</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>
|
||||
<p>Incremental bumping of a compiler pre-defined macro,
|
||||
__GXX_ABI_VERSION. This macro is defined as the version of the
|
||||
compiler v3 ABI, with g++ 3.0.x being version 100. This macro will
|
||||
be automatically defined whenever g++ is used (the curious can
|
||||
test this by invoking g++ with the '-v' flag.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This macro is defined in the file "lang-specs.h" in the gcc/cp directory.
|
||||
Later versions define it in "c-common.c" in the gcc directory.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.x: 100</li>
|
||||
<li>gcc-3.1.x: 100 (Error, should be 101)</li>
|
||||
<li>gcc-3.2.x: 102</li>
|
||||
<li>gcc-3.3.x: 102</li>
|
||||
<li>gcc-3.4.x: 1002</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>
|
||||
<p>Changes to the default compiler option for
|
||||
<code>-fabi-version</code>.
|
||||
</p>
|
||||
<p>
|
||||
It is versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.x: (Error, not versioned) </li>
|
||||
<li>gcc-3.1.x: (Error, not versioned) </li>
|
||||
<li>gcc-3.2.x: <code>-fabi-version=1</code></li>
|
||||
<li>gcc-3.3.x: <code>-fabi-version=1</code></li>
|
||||
<li>gcc-3.4.x: <code>-fabi-version=2</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>
|
||||
<p>Incremental bumping of a library pre-defined macro. For releases
|
||||
before 3.4.0, the macro is __GLIBCPP__. For later releases, it's
|
||||
__GLIBCXX__. (The libstdc++ project generously changed from CPP to
|
||||
CXX throughout its source to allow the "C" pre-processor the CPP
|
||||
macro namespace.) These macros are defined as the date the library
|
||||
was released, in compressed ISO date format, as an unsigned long.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In addition, the pre-defined macro is defined in the file
|
||||
"c++config" in the "libstdc++-v3/include/bits" directory and is
|
||||
changed every night by an automated script.
|
||||
</p>
|
||||
<p>
|
||||
It is versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: 20010615</li>
|
||||
<li>gcc-3.0.1: 20010819</li>
|
||||
<li>gcc-3.0.2: 20011023</li>
|
||||
<li>gcc-3.0.3: 20011220</li>
|
||||
<li>gcc-3.0.4: 20020220</li>
|
||||
<li>gcc-3.1.0: 20020514</li>
|
||||
<li>gcc-3.1.1: 20020725</li>
|
||||
<li>gcc-3.2.0: 20020814</li>
|
||||
<li>gcc-3.2.1: 20021119</li>
|
||||
<li>gcc-3.2.2: 20030205</li>
|
||||
<li>gcc-3.2.3: 20030422</li>
|
||||
<li>gcc-3.3.0: 20030513</li>
|
||||
<li>gcc-3.3.1: 20030804</li>
|
||||
<li>gcc-3.3.2: 20031016</li>
|
||||
<li>gcc-3.3.3: 20040214</li>
|
||||
<li>gcc-3.4.0: 20040419</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Incremental bumping of a library pre-defined macro,
|
||||
_GLIBCPP_VERSION. This macro is defined as the released version of
|
||||
the library, as a string literal. This is only implemented in
|
||||
gcc-3.1.0 releases and higher, and is deprecated in 3.4.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This macro is defined in the file "c++config" in the
|
||||
"libstdc++-v3/include/bits" directory and is generated
|
||||
automatically by autoconf as part of the configure-time generation
|
||||
of config.h.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: "3.0.0"</li>
|
||||
<li>gcc-3.0.1: "3.0.0" (Error, should be "3.0.1")</li>
|
||||
<li>gcc-3.0.2: "3.0.0" (Error, should be "3.0.2")</li>
|
||||
<li>gcc-3.0.3: "3.0.0" (Error, should be "3.0.3")</li>
|
||||
<li>gcc-3.0.4: "3.0.0" (Error, should be "3.0.4")</li>
|
||||
<li>gcc-3.1.0: "3.1.0"</li>
|
||||
<li>gcc-3.1.1: "3.1.1"</li>
|
||||
<li>gcc-3.2.0: "3.2"</li>
|
||||
<li>gcc-3.2.1: "3.2.1"</li>
|
||||
<li>gcc-3.2.2: "3.2.2"</li>
|
||||
<li>gcc-3.2.3: "3.2.3"</li>
|
||||
<li>gcc-3.3.0: "3.3"</li>
|
||||
<li>gcc-3.3.1: "3.3.1"</li>
|
||||
<li>gcc-3.3.2: "3.3.2"</li>
|
||||
<li>gcc-3.3.3: "3.3.3"</li>
|
||||
<li>gcc-3.4.0: "version-unused"</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Matching each specific C++ compiler release to a specific set of
|
||||
C++ include files. This is only implemented in gcc-3.1.1 releases
|
||||
and higher.
|
||||
</p>
|
||||
<p>
|
||||
All C++ includes are installed in include/c++, then nest in a
|
||||
directory hierarchy corresponding to the C++ compiler's released
|
||||
version. This version corresponds to the variable "gcc_version" in
|
||||
"libstdc++-v3/acinclude.m4," and more details can be found in that
|
||||
file's macro GLIBCPP_CONFIGURE.
|
||||
</p>
|
||||
<p>
|
||||
C++ includes are versioned as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>gcc-3.0.0: include/g++-v3</li>
|
||||
<li>gcc-3.0.1: include/g++-v3</li>
|
||||
<li>gcc-3.0.2: include/g++-v3</li>
|
||||
<li>gcc-3.0.3: include/g++-v3</li>
|
||||
<li>gcc-3.0.4: include/g++-v3</li>
|
||||
<li>gcc-3.1.0: include/g++-v3</li>
|
||||
<li>gcc-3.1.1: include/c++/3.1.1</li>
|
||||
<li>gcc-3.2.0: include/c++/3.2</li>
|
||||
<li>gcc-3.2.1: include/c++/3.2.1</li>
|
||||
<li>gcc-3.2.2: include/c++/3.2.2</li>
|
||||
<li>gcc-3.2.3: include/c++/3.2.3</li>
|
||||
<li>gcc-3.3.0: include/c++/3.3</li>
|
||||
<li>gcc-3.3.1: include/c++/3.3.1</li>
|
||||
<li>gcc-3.3.2: include/c++/3.3.2</li>
|
||||
<li>gcc-3.3.3: include/c++/3.3.3</li>
|
||||
<li>gcc-3.4.0: include/c++/3.4.0</li>
|
||||
</ul>
|
||||
</li>
|
||||
<p></p>
|
||||
</ul>
|
||||
<p>
|
||||
Taken together, these techniques can accurately specify interface
|
||||
and implementation changes in the GNU C++ tools themselves. Used
|
||||
properly, they allow both the GNU C++ tools implementation, and
|
||||
programs using them, an evolving yet controlled development that
|
||||
maintains backward compatibility.
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<h5 class="left">
|
||||
<a name="requirements"> Minimum requirements for a versioned ABI </a>
|
||||
</h5>
|
||||
<p>
|
||||
Minimum environment that supports a versioned ABI: A supported
|
||||
dynamic linker, a GNU linker of sufficient vintage to understand
|
||||
demangled C++ name globbing (ld), a shared executable compiled with
|
||||
g++, and shared libraries (libgcc_s, libstdc++-v3) compiled by a
|
||||
compiler (g++) with a compatible ABI. Phew.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
On top of all that, an additional constraint: libstdc++ did not
|
||||
attempt to version symbols (or age gracefully, really) until version
|
||||
3.1.0.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Most modern Linux and BSD versions, particularly ones using
|
||||
gcc-3.1.x tools and more recent vintages, will meet the requirements above.
|
||||
</p>
|
||||
|
||||
|
||||
<h5 class="left">
|
||||
<a name="config"> What configure options impact symbol versioning? </a>
|
||||
</h5>
|
||||
<p>
|
||||
It turns out that most of the configure options that change default
|
||||
behavior will impact the mangled names of exported symbols, and thus
|
||||
impact versioning and compatibility.
|
||||
</p>
|
||||
|
||||
</p>
|
||||
For more information on configure options, including ABI impacts, see:
|
||||
http://gcc.gnu.org/onlinedocs/libstdc++/configopts.html
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There is one flag that explicitly deals with symbol versioning:
|
||||
--enable-symvers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In particular, libstdc++-v3/acinclude.m4 has a macro called
|
||||
GLIBCXX_ENABLE_SYMVERS that defaults to yes (or the argument passed
|
||||
in via --enable-symvers=foo). At that point, the macro attempts to
|
||||
make sure that all the requirement for symbol versioning are in
|
||||
place. For more information, please consult acinclude.m4.
|
||||
</p>
|
||||
|
||||
|
||||
<h5 class="left">
|
||||
<a name="active"> How to tell if symbol versioning is, indeed, active? </a>
|
||||
</h5>
|
||||
<p>
|
||||
When the GNU C++ library is being built with symbol versioning on,
|
||||
you should see the following at configure time for libstdc++-v3:
|
||||
</p>
|
||||
|
||||
|
||||
<code> checking versioning on shared library symbols... gnu</code>
|
||||
|
||||
<p>
|
||||
If you don't see this line in the configure output, or if this line
|
||||
appears but the last word is 'no', then you are out of luck.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the compiler is pre-installed, a quick way to test is to compile
|
||||
the following (or any) simple C++ file and link it to the shared
|
||||
libstdc++ library:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{ std::cout << "hello" << std::endl; return 0; }
|
||||
|
||||
%g++ hello.cc -o hello.out
|
||||
|
||||
%ldd hello.out
|
||||
libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x00764000)
|
||||
libm.so.6 => /lib/tls/libm.so.6 (0x004a8000)
|
||||
libgcc_s.so.1 => /mnt/hd/bld/gcc/gcc/libgcc_s.so.1 (0x40016000)
|
||||
libc.so.6 => /lib/tls/libc.so.6 (0x0036d000)
|
||||
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00355000)
|
||||
|
||||
%nm hello.out
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If you see symbols in the resulting output with "GLIBCXX_3" as part
|
||||
of the name, then the executable is versioned. Here's an example:
|
||||
</p>
|
||||
|
||||
<code> U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4 </code>
|
||||
|
||||
<h3 class="left">
|
||||
<a name="ABI allowed">Library allowed ABI changes</a>
|
||||
</h3>
|
||||
<p>
|
||||
The following will cause the library minor version number to
|
||||
increase, say from "libstdc++.so.3.0.4" to "libstdc++.so.3.0.5".
|
||||
</p>
|
||||
<ul>
|
||||
<li>adding an exported global or static data member</li>
|
||||
<li>adding an exported function, static or non-virtual member function</li>
|
||||
<li>adding an exported symbol or symbols by additional instantiations</li>
|
||||
</ul>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Other allowed changes are possible.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 class="left">
|
||||
<a name="ABI disallowed">Library disallowed ABI changes</a>
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
The following non-exhaustive list will cause the library major version
|
||||
number to increase, say from "libstdc++.so.3.0.4" to
|
||||
"libstdc++.so.4.0.0".
|
||||
</p>
|
||||
<ul>
|
||||
<li>changes in the gcc/g++ compiler ABI</li>
|
||||
<li>changing size of an exported symbol</li>
|
||||
<li>changing alignment of an exported symbol</li>
|
||||
<li>changing the layout of an exported symbol</li>
|
||||
<li>changing mangling on an exported symbol</li>
|
||||
<li>deleting an exported symbol</li>
|
||||
<li>changing the inheritance properties of a type by adding or removing
|
||||
base classes</li>
|
||||
<li>
|
||||
changing the size, alignment, or layout of types
|
||||
specified in the C++ standard. These may not necessarily be
|
||||
instantiated or otherwise exported in the library binary, and
|
||||
include all the required locale facets, as well as things like
|
||||
std::basic_streambuf, et al.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="left">
|
||||
<a name="implementation">Library implementation strategy</a>
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Separation of interface and implementation</li>
|
||||
<p>This is accomplished by two techniques that separate the API from
|
||||
the ABI: forcing undefined references to link against a library binary
|
||||
for definitions.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Include files have declarations, source files have defines</li>
|
||||
|
||||
<p> For non-templatized types, such as much of <code>class
|
||||
locale</code>, the appropriate standard C++ include, say
|
||||
<code>locale</code>, can contain full declarations, while various
|
||||
source files (say <code> locale.cc, locale_init.cc,
|
||||
localename.cc</code>) contain definitions.</p>
|
||||
|
||||
<li>Extern template on required types</li>
|
||||
|
||||
<p>For parts of the standard that have an explicit list of required
|
||||
instantiations, the GNU extension syntax <code> extern template
|
||||
</code> can be used to control where template definitions
|
||||
reside. By marking required instantiations as <code> extern
|
||||
template </code> in include files, and providing explicit
|
||||
instantiations in the appropriate instantiation files, non-inlined
|
||||
template functions can be versioned. This technique is mostly used
|
||||
on parts of the standard that require <code> char</code> and <code>
|
||||
wchar_t</code> instantiations, and includes <code>
|
||||
basic_string</code>, the locale facets, and the types in <code>
|
||||
iostreams</code>.</p>
|
||||
|
||||
</ul>
|
||||
<p> In addition, these techniques have the additional benefit that
|
||||
they reduce binary size, which can increase runtime performance.
|
||||
</p>
|
||||
|
||||
<li>Namespaces linking symbol definitions to export mapfiles</li>
|
||||
|
||||
<p>All symbols in the shared library binary are processed by a linker
|
||||
script at build time that either allows or disallows external
|
||||
linkage. Because of this, some symbols, regardless of normal C/C++
|
||||
linkage, are not visible. Symbols that are internal have several
|
||||
appealing characteristics: by not exporting the symbols, there are no
|
||||
relocations when the shared library is started and thus this makes for
|
||||
faster runtime loading performance by the underlying dynamic loading
|
||||
mechanism. In addition, they have the possibility of changing without
|
||||
impacting ABI compatibility.
|
||||
</p>
|
||||
|
||||
<p>The following namespaces are transformed by the mapfile:</p>
|
||||
|
||||
<ul>
|
||||
<li><code>namespace std</code></li>
|
||||
<p> Defaults to exporting all symbols in label
|
||||
<code>GLIBCXX</code> that do not begin with an underscore, ie
|
||||
<code>__test_func</code> would not be exported by default. Select
|
||||
exceptional symbols are allowed to be visible.</p>
|
||||
|
||||
<li><code>namespace __gnu_cxx</code></li>
|
||||
<p> Defaults to not exporting any symbols in label
|
||||
<code>GLIBCXX</code>, select items are allowed to be visible.</p>
|
||||
|
||||
<li><code>namespace __gnu_internal</code></li>
|
||||
<p> Defaults to not exported, no items are allowed to be visible.</p>
|
||||
|
||||
<li><code>namespace __cxxabiv1</code>, aliased to <code> namespace abi</code></li>
|
||||
<p> Defaults to not exporting any symbols in label
|
||||
<code>CXXABI</code>, select items are allowed to be visible.</p>
|
||||
</ul>
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<li>Freezing the API</li>
|
||||
<p>Disallowed changes, as above, are not made on a stable release
|
||||
branch. Enforcement tends to be less strict with GNU extensions that
|
||||
standard includes.</p> </ul>
|
||||
|
||||
<h3 class="left">
|
||||
<a name="ABI testing">Testing ABI changes</a>
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Testing for GNU C++ ABI changes is composed of two distinct areas:
|
||||
testing the C++ compiler (g++) for compiler changes, and testing the
|
||||
C++ library (libstdc++) for library changes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Testing the C++ compiler ABI can be done various ways.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One.
|
||||
Intel ABI checker. More information can be obtained
|
||||
<a href="http://developer.intel.com/software/products/opensource/">here.</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Two.
|
||||
The second is yet unreleased, but has been announced on the gcc
|
||||
mailing list. It is yet unspecified if these tools will be freely
|
||||
available, and able to be included in a GNU project. Please contact
|
||||
Mark Mitchell (mark@codesourcery.com) for more details, and current
|
||||
status.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Three.
|
||||
Involves using the vlad.consistency test framework. This has also been
|
||||
discussed on the gcc mailing lists.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Testing the C++ library ABI can also be done various ways.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One.
|
||||
(Brendan Kehoe, Jeff Law suggestion to run 'make check-c++' two ways,
|
||||
one with a new compiler and an old library, and the other with an old
|
||||
compiler and a new library, and look for testsuite regressions)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Details on how to set this kind of test up can be found here:
|
||||
http://gcc.gnu.org/ml/gcc/2002-08/msg00142.html
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Two.
|
||||
Use the 'make check-abi' rule in the libstdc++-v3 Makefile.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This is a proactive check the library ABI. Currently, exported symbol
|
||||
names that are either weak or defined are checked against a last known
|
||||
good baseline. Currently, this baseline is keyed off of 3.2.0
|
||||
binaries, as this was the last time the .so number was incremented. In
|
||||
addition, all exported names are demangled, and the exported objects
|
||||
are checked to make sure they are the same size as the same object in
|
||||
the baseline.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This dataset is insufficient, yet a start. Also needed is a
|
||||
comprehensive check for all user-visible types part of the standard
|
||||
library for sizeof() and alignof() changes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Verifying compatible layouts of objects is not even attempted. It
|
||||
should be possible to use sizeof, alignof, and offsetof to compute
|
||||
offsets for each structure and type in the standard library, saving to
|
||||
another datafile. Then, compute this in a similar way for new
|
||||
binaries, and look for differences.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another approach might be to use the -fdump-class-hierarchy flag to
|
||||
get information. However, currently this approach gives insufficient
|
||||
data for use in library testing, as class data members, their offsets,
|
||||
and other detailed data is not displayed with this flag.
|
||||
(See g++/7470 on how this was used to find bugs.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Perhaps there are other C++ ABI checkers. If so, please notify
|
||||
us. We'd like to know about them!
|
||||
</p>
|
||||
|
||||
<h3 class="left">
|
||||
<a name="ABI multi testing">Testing Multi-ABI binaries</a>
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
A "C" application, dynamically linked to two shared libraries, liba,
|
||||
libb. The dependent library liba is C++ shared library compiled with
|
||||
gcc-3.3.x, and uses io, exceptions, locale, etc. The dependent library
|
||||
libb is a C++ shared library compiled with gcc-3.4.x, and also uses io,
|
||||
exceptions, locale, etc.
|
||||
</p>
|
||||
|
||||
<p> As above, libone is constructed as follows: </p>
|
||||
<pre>
|
||||
%$bld/H-x86-gcc-3.4.0/bin/g++ -fPIC -DPIC -c a.cc
|
||||
|
||||
%$bld/H-x86-gcc-3.4.0/bin/g++ -shared -Wl,-soname -Wl,libone.so.1 -Wl,-O1 -Wl,-z,defs a.o -o libone.so.1.0.0
|
||||
|
||||
%ln -s libone.so.1.0.0 libone.so
|
||||
|
||||
%$bld/H-x86-gcc-3.4.0/bin/g++ -c a.cc
|
||||
|
||||
%ar cru libone.a a.o
|
||||
</pre>
|
||||
|
||||
<p> And, libtwo is constructed as follows: </p>
|
||||
|
||||
<pre>
|
||||
%$bld/H-x86-gcc-3.3.3/bin/g++ -fPIC -DPIC -c b.cc
|
||||
|
||||
%$bld/H-x86-gcc-3.3.3/bin/g++ -shared -Wl,-soname -Wl,libtwo.so.1 -Wl,-O1 -Wl,-z,defs b.o -o libtwo.so.1.0.0
|
||||
|
||||
%ln -s libtwo.so.1.0.0 libtwo.so
|
||||
|
||||
%$bld/H-x86-gcc-3.3.3/bin/g++ -c b.cc
|
||||
|
||||
%ar cru libtwo.a b.o
|
||||
</pre>
|
||||
|
||||
<p> ...with the resulting libraries looking like </p>
|
||||
<pre>
|
||||
%ldd libone.so.1.0.0
|
||||
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x40016000)
|
||||
libm.so.6 => /lib/tls/libm.so.6 (0x400fa000)
|
||||
libgcc_s.so.1 => /mnt/hd/bld/gcc/gcc/libgcc_s.so.1 (0x4011c000)
|
||||
libc.so.6 => /lib/tls/libc.so.6 (0x40125000)
|
||||
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00355000)
|
||||
|
||||
%ldd libtwo.so.1.0.0
|
||||
libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40027000)
|
||||
libm.so.6 => /lib/tls/libm.so.6 (0x400e1000)
|
||||
libgcc_s.so.1 => /mnt/hd/bld/gcc/gcc/libgcc_s.so.1 (0x40103000)
|
||||
libc.so.6 => /lib/tls/libc.so.6 (0x4010c000)
|
||||
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00355000)
|
||||
|
||||
</pre>
|
||||
|
||||
<p> Then, the "C" compiler is used to compile a source file that uses
|
||||
functions from each library.</p>
|
||||
<pre>
|
||||
gcc test.c -g -O2 -L. -lone -ltwo /usr/lib/libstdc++.so.5 /usr/lib/libstdc++.so.6
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Which gives the expected:
|
||||
</p>
|
||||
<pre>
|
||||
%ldd a.out
|
||||
libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x00764000)
|
||||
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x40015000)
|
||||
libc.so.6 => /lib/tls/libc.so.6 (0x0036d000)
|
||||
libm.so.6 => /lib/tls/libm.so.6 (0x004a8000)
|
||||
libgcc_s.so.1 => /mnt/hd/bld/gcc/gcc/libgcc_s.so.1 (0x400e5000)
|
||||
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00355000)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This resulting binary, when executed, will be able to safely use code
|
||||
from both liba, and the dependent libstdc++.so.6, and libb, with the
|
||||
dependent libstdc++.so.5.
|
||||
</p>
|
||||
|
||||
<h3 class="left">
|
||||
<a name="references">Bibliography / Further Reading</a>
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
ABIcheck, a vague idea of checking ABI compatibility
|
||||
http://abicheck.sourceforge.net/
|
||||
|
||||
<p>
|
||||
C++ ABI reference
|
||||
http://www.codesourcery.com/cxx-abi/
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Intel ABI documentation
|
||||
"Intel® Compilers for Linux* -Compatibility with the GNU Compilers"
|
||||
(included in icc 6.0)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Sun Solaris 2.9 docs
|
||||
Linker and Libraries Guide (document 816-1386)
|
||||
C++ Migration Guide (document 816-2459)
|
||||
http://docs.sun.com/db/prod/solaris.9
|
||||
http://docs.sun.com/?p=/doc/816-1386&a=load
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Ulrich Drepper, "ELF Symbol Versioning"
|
||||
http://people.redhat.com/drepper/symbol-versioning
|
||||
</p>
|
@ -1,389 +0,0 @@
|
||||
|
||||
2002-10-14 Benjamin Kosnik
|
||||
|
||||
Description of the libstdc++ ABI.
|
||||
|
||||
I. What is an ABI? What's covered? What's not?
|
||||
|
||||
- scope of document, of use to system integrators.
|
||||
|
||||
- What's the deal with C++? Why can't different compiler's object
|
||||
files link with each other? Bug? Feature?
|
||||
|
||||
- compilation includes and linked library binary must match up..
|
||||
|
||||
- shared library only, static is immutable.
|
||||
|
||||
- What's an ABI?
|
||||
|
||||
- library ABI, compiler ABI different issues, (but related)
|
||||
|
||||
- GNU C++ does not have a compiler command line option to switch
|
||||
between various different C++ ABIs. For instance, there is no way to
|
||||
switch between the gcc-3.0.x ABI, gcc-3.1.x ABI, and the gcc-3.2.x
|
||||
ABI during compilation. Other C++ compilers do allow this, and some
|
||||
g++ command line options may change the ABI (-fno-exceptions, see
|
||||
the complete list), but there is no version switch. Sorry.
|
||||
|
||||
To use a specific C++ABI, one must use the corresponding GNU C++
|
||||
toolchain.
|
||||
|
||||
- How can this complexity be managed? What does C++ versioning mean?
|
||||
Because library and compiler changes often make binaries compiled
|
||||
with one version of the GNU tools incompatible with binaries
|
||||
compiled with other (either newer or older) versions of the same GNU
|
||||
tools, specific techniques are used to make managing this complexity
|
||||
easier.
|
||||
|
||||
The following techniques are used:
|
||||
|
||||
- Release versioning on the libgcc_s.so binary.
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.0: libgcc_s.so.1
|
||||
gcc-3.0.1: libgcc_s.so.1
|
||||
gcc-3.0.2: libgcc_s.so.1
|
||||
gcc-3.0.3: libgcc_s.so.1
|
||||
gcc-3.0.4: libgcc_s.so.1
|
||||
gcc-3.1.0: libgcc_s.so.1
|
||||
gcc-3.1.1: libgcc_s.so.1
|
||||
gcc-3.2.0: libgcc_s.so.1
|
||||
|
||||
|
||||
- Release versioning on the libstdc++.so binary.
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.0: libstdc++.so.3.0.0
|
||||
gcc-3.0.1: libstdc++.so.3.0.1
|
||||
gcc-3.0.2: libstdc++.so.3.0.2
|
||||
gcc-3.0.3: libstdc++.so.3.0.2 (Error, should be libstdc++.so.3.0.3)
|
||||
gcc-3.0.4: libstdc++.so.3.0.4
|
||||
gcc-3.1.0: libstdc++.so.4.0.0
|
||||
gcc-3.1.1: libstdc++.so.4.0.1
|
||||
gcc-3.2.0: libstdc++.so.5.0.0
|
||||
|
||||
|
||||
- Symbol versioning on the libgcc_s.so binary.
|
||||
|
||||
file: gcc/libgcc-std.ver
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.0: GCC_3.0
|
||||
gcc-3.0.1: GCC_3.0
|
||||
gcc-3.0.2: GCC_3.0
|
||||
gcc-3.0.3: GCC_3.0
|
||||
gcc-3.0.4: GCC_3.0
|
||||
gcc-3.1.0: GCC_3.0
|
||||
gcc-3.1.1: GCC_3.0
|
||||
gcc-3.2.0: GCC_3.0
|
||||
|
||||
|
||||
- Symbol versioning on the libstdc++.so binary.
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.0: (Error, unversioned)
|
||||
gcc-3.0.1: (Error, unversioned)
|
||||
gcc-3.0.2: (Error, unversioned)
|
||||
gcc-3.0.3: (Error, unversioned)
|
||||
gcc-3.0.4: (Error, unversioned)
|
||||
gcc-3.1.0: GLIBCPP_3.1, CXXABI_1
|
||||
gcc-3.1.1: GLIBCPP_3.1, CXXABI_1
|
||||
gcc-3.2.0: GLIBCPP_3.2, CXXABI_1.2
|
||||
|
||||
file: libstdc++-v3/config/linker-map.gnu
|
||||
|
||||
|
||||
- Incremental bumping of a compiler pre-defined macro,
|
||||
__GXX_ABI_VERSION. This macro is defined as the version of the
|
||||
compiler v3 ABI, with g++ 3.0.x being version 100. This macro will
|
||||
be automatically defined whenever g++ is used (the curious can
|
||||
test this by invoking g++ with the '-v' flag.)
|
||||
|
||||
This macro is defined in the file "lang-specs.h" in the gcc/cp directory.
|
||||
Later versions define it in "c-common.c" in the gcc directory.
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.x: 100
|
||||
gcc-3.1.x: 100 (Error, should be 101)
|
||||
gcc-3.2.x: 102
|
||||
|
||||
|
||||
- Incremental bumping of a library pre-defined macro, __GLIBCPP__ or
|
||||
__GLIBCXX__. This macro is defined as the date the library was
|
||||
released, in compressed ISO date format, as an unsigned long.
|
||||
|
||||
This macro is defined in the file "c++config" in the
|
||||
"libstdc++-v3/include/bits" directory and is changed every night
|
||||
by an automated script.
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.0: 20010615
|
||||
gcc-3.0.1: 20010819
|
||||
gcc-3.0.2: 20011023
|
||||
gcc-3.0.3: 20011220
|
||||
gcc-3.0.4: 20020220
|
||||
gcc-3.1.0: 20020514
|
||||
gcc-3.1.1: 20020725
|
||||
gcc-3.2.0: 20020814
|
||||
|
||||
|
||||
- Incremental bumping of a library pre-defined macro,
|
||||
_GLIBCPP_VERSION. This macro is defined as the released version of
|
||||
the library, as a string literal. This is only implemented in
|
||||
gcc-3.1.0 releases and higher, and changed to _GLIBCXX_VERSION in 3.4.
|
||||
|
||||
This macro is defined in the file "c++config" in the
|
||||
"libstdc++-v3/include/bits" directory and is generated
|
||||
automatically by autoconf as part of the configure-time generation
|
||||
of config.h.
|
||||
|
||||
It is versioned as follows:
|
||||
gcc-3.0.0: "3.0.0"
|
||||
gcc-3.0.1: "3.0.0" (Error, should be "3.0.1")
|
||||
gcc-3.0.2: "3.0.0" (Error, should be "3.0.2")
|
||||
gcc-3.0.3: "3.0.0" (Error, should be "3.0.3")
|
||||
gcc-3.0.4: "3.0.0" (Error, should be "3.0.4")
|
||||
gcc-3.1.0: "3.1.0"
|
||||
gcc-3.1.1: "3.1.1"
|
||||
gcc-3.2.0: "3.2"
|
||||
|
||||
|
||||
- Matching each specific C++ compiler release to a specific set of
|
||||
C++ include files. This is only implemented in gcc-3.1.1 releases
|
||||
and higher.
|
||||
|
||||
All C++ includes are installed in include/c++, then nest in a
|
||||
directory hierarchy corresponding to the C++ compiler's released
|
||||
version. This version corresponds to the variable "gcc_version" in
|
||||
"libstdc++-v3/acinclude.m4," and more details can be found in that
|
||||
file's macro GLIBCPP_CONFIGURE.
|
||||
|
||||
C++ includes are versioned as follows:
|
||||
gcc-3.0.0: include/g++-v3
|
||||
gcc-3.0.1: include/g++-v3
|
||||
gcc-3.0.2: include/g++-v3
|
||||
gcc-3.0.3: include/g++-v3
|
||||
gcc-3.0.4: include/g++-v3
|
||||
gcc-3.1.0: include/g++-v3
|
||||
gcc-3.1.1: include/c++/3.1.1
|
||||
gcc-3.2.0: include/c++/3.2
|
||||
|
||||
Taken together, these techniques can accurately specify interface
|
||||
and implementation changes in the GNU C++ tools themselves. Used
|
||||
properly, they allow both the GNU C++ tools implementation, and
|
||||
programs using them, an evolving yet controlled development that
|
||||
maintains backward compatibility.
|
||||
|
||||
- Minimum environment that supports a versioned ABI: what's needed? A
|
||||
supported dynamic linker, a GNU linker of sufficient vintage to
|
||||
understand demangled C++ name globbing (ld), a shared executable
|
||||
compiled with g++, and shared libraries (libgcc_s, libstdc++-v3)
|
||||
compiled by a compiler (g++) with a compatible ABI. Phew.
|
||||
|
||||
On top of all that, an additional constraint: libstdc++ did not
|
||||
attempt to version symbols (or age gracefully, really) until version
|
||||
3.1.0.
|
||||
|
||||
Most modern Linux and BSD versions, particularly ones using
|
||||
gcc-3.1.x tools, will meet the requirements above.
|
||||
|
||||
- What configure options impact symbol versioning?
|
||||
|
||||
It turns out that most of the configure options that change default
|
||||
behavior will impact the mangled names of exported symbols, and thus
|
||||
impact versioning and compatibility.
|
||||
|
||||
For more information on configure options, including ABI impacts, see:
|
||||
http://gcc.gnu.org/onlinedocs/libstdc++/configopts.html
|
||||
|
||||
There is one flag that explicitly deals with symbol versioning:
|
||||
--enable-symvers.
|
||||
|
||||
In particular, libstdc++-v3/acinclude.m4 has a macro called
|
||||
GLIBCXX_ENABLE_SYMVERS that defaults to yes (or the argument passed
|
||||
in via --enable-symvers=foo). At that point, the macro attempts to
|
||||
make sure that all the requirement for symbol versioning are in
|
||||
place. For more information, please consult acinclude.m4.
|
||||
|
||||
- How can I tell if symbol versioning is, indeed, active?
|
||||
|
||||
When the GNU C++ library is being built with symbol versioning on,
|
||||
you should see the following at configure time for libstdc++-v3:
|
||||
|
||||
checking versioning on shared library symbols... gnu
|
||||
|
||||
If you don't see this line in the configure output, or if this line
|
||||
appears but the last word is 'no', then you are out of luck.
|
||||
|
||||
If the compiler is pre-installed, a quick way to test is to compile
|
||||
the following (or any) simple C++ file:
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{ std::cout << "hello" << std::endl; return 0; }
|
||||
|
||||
%g++ hello.cc -o hello.out
|
||||
%nm hello.out
|
||||
|
||||
If you see symbols in the resulting output with "GLIBCPP_3.x" as part
|
||||
of the name, then the executable is versioned. Here's an example:
|
||||
|
||||
U _ZNSt8ios_base4InitC1Ev@@GLIBCPP_3.1
|
||||
|
||||
|
||||
II. Library ABI changes
|
||||
|
||||
The following will cause the library major version number to
|
||||
increase, say from "libstdc++.so.3.0.4" to "libstdc++.so.4.0.0".
|
||||
|
||||
- (anything) changing in the gcc/g++ compiler ABI
|
||||
|
||||
- (anything) changing size of an exported symbol
|
||||
|
||||
- (anything) changing alignment of an exported symbol
|
||||
|
||||
- (anything) changing the layout of an exported symbol
|
||||
|
||||
- (anything) changing mangling on an exported symbol
|
||||
|
||||
- (anything) deleting an exported symbol
|
||||
|
||||
- (anything) changing the size, alignment, or layout of types
|
||||
specified in the C++ standard. These may not necessarily be
|
||||
instantiated or otherwise exported in the library binary, and
|
||||
include all the required locale facets, as well as things like
|
||||
std::basic_streambuf, et al.
|
||||
|
||||
Note: adding an exported symbol, if it's in a new and dependent
|
||||
interface name, is ok.
|
||||
|
||||
The following will cause the library revision version number to
|
||||
increase, say from "libstdc++.so.5.0.0" to "libstdc++.so.5.0.1".
|
||||
|
||||
- any release of the gcc toolchain.
|
||||
|
||||
|
||||
III. Versioning
|
||||
|
||||
- include files
|
||||
|
||||
- versioning headers with version, why necessary
|
||||
(need to control member/non-member functions, add delete files)
|
||||
|
||||
- shared library binaries
|
||||
|
||||
- release versions
|
||||
|
||||
- libtool versions
|
||||
|
||||
- when does so version get a bump? what are the options?
|
||||
|
||||
- how is the link map used?
|
||||
|
||||
- in an non-abi breaking minor release, how are symbols added?
|
||||
removed?
|
||||
|
||||
- in an abi-breaking major release, what happens? symbol fall back
|
||||
|
||||
|
||||
IV. Testing ABI changes
|
||||
|
||||
Testing for GNU C++ ABI changes is composed of two distinct areas:
|
||||
testing the C++ compiler (g++) for compiler changes, and testing the
|
||||
C++ library (libstdc++) for library changes.
|
||||
|
||||
Testing the C++ compiler ABI can be done various ways.
|
||||
|
||||
One.
|
||||
Intel ABI checker. More information can be obtained
|
||||
<a href="http://developer.intel.com/software/products/opensource/">here.</a>
|
||||
|
||||
Two.
|
||||
The second is yet unreleased, but has been announced on the gcc
|
||||
mailing list. It is yet unspecified if these tools will be freely
|
||||
available, and able to be included in a GNU project. Please contact
|
||||
Mark Mitchell (mark@codesourcery.com) for more details, and current
|
||||
status.
|
||||
|
||||
Three.
|
||||
Involves using the vlad.consistency test framework. This has also been
|
||||
discussed on the gcc mailing lists.
|
||||
|
||||
Testing the C++ library ABI can also be done various ways.
|
||||
|
||||
One.
|
||||
(Brendan Kehoe, Jeff Law suggestion to run 'make check-c++' two ways,
|
||||
one with a new compiler and an old library, and the other with an old
|
||||
compiler and a new library, and look for testsuite regressions)
|
||||
|
||||
Details on how to set this kind of test up can be found here:
|
||||
http://gcc.gnu.org/ml/gcc/2002-08/msg00142.html
|
||||
|
||||
Two.
|
||||
Use the 'make check-abi' rule in the libstdc++-v3 Makefile.
|
||||
|
||||
This is a proactive check the library ABI. Currently, exported symbol
|
||||
names that are either weak or defined are checked against a last known
|
||||
good baseline. Currently, this baseline is keyed off of 3.2.0
|
||||
binaries, as this was the last time the .so number was incremented. In
|
||||
addition, all exported names are demangled, and the exported objects
|
||||
are checked to make sure they are the same size as the same object in
|
||||
the baseline.
|
||||
|
||||
This dataset is insufficient, yet a start. Also needed is a
|
||||
comprehensive check for all user-visible types part of the standard
|
||||
library for sizeof() and alignof() changes.
|
||||
|
||||
Verifying compatible layouts of objects is not even attempted. It
|
||||
should be possible to use sizeof, alignof, and offsetof to compute
|
||||
offsets for each structure and type in the standard library, saving to
|
||||
another datafile. Then, compute this in a similar way for new
|
||||
binaries, and look for differences.
|
||||
|
||||
Another approach might be to use the -fdump-class-hierarchy flag to
|
||||
get information. However, currently this approach gives insufficient
|
||||
data for use in library testing, as class data members, their offsets,
|
||||
and other detailed data is not displayed with this flag.
|
||||
(See g++/7470 on how this was used to find bugs.)
|
||||
|
||||
Perhaps there are other C++ ABI checkers. If so, please notify
|
||||
us. We'd like to know about them!
|
||||
|
||||
|
||||
V. Issues not directly addressed, and possible suggestions
|
||||
|
||||
- what to do about multi-ABI systems (nathan scenario)?
|
||||
|
||||
- compatibility libs
|
||||
|
||||
--enable-version-specific-runtime-libs
|
||||
|
||||
- Alexandre Oliva proposal to have extended name attributes, modify ld
|
||||
|
||||
- directory-level versioning
|
||||
|
||||
- wrapping C++ API's in "C" to use the C ABI.
|
||||
|
||||
|
||||
V. References
|
||||
|
||||
ABIcheck, a vague idea of checking ABI compatibility
|
||||
http://abicheck.sourceforge.net/
|
||||
|
||||
C++ ABI reference
|
||||
http://www.codesourcery.com/cxx-abi/
|
||||
|
||||
Intel ABI documentation
|
||||
"Intel® Compilers for Linux* -Compatibility with the GNU Compilers"
|
||||
(included in icc 6.0)
|
||||
|
||||
Sun Solaris 2.9 docs
|
||||
Linker and Libraries Guide (document 816-1386)
|
||||
C++ Migration Guide (document 816-2459)
|
||||
http://docs.sun.com/db/prod/solaris.9
|
||||
http://docs.sun.com/?p=/doc/816-1386&a=load
|
||||
|
||||
Ulrich Drepper, "ELF Symbol Versioning"
|
||||
http://people.redhat.com/drepper/symbol-versioning
|
||||
|
@ -30,7 +30,7 @@
|
||||
<ul>
|
||||
<li><a href="17_intro/COPYING">License</a>
|
||||
- GPL v2 license terms</li>
|
||||
<li><a href="abi.txt">ABI Policy and Guidelines</a></li>
|
||||
<li><a href="abi.html">ABI Policy and Guidelines</a></li>
|
||||
<li><a href="17_intro/BUGS">BUGS</a></li>
|
||||
<li><a href="17_intro/PROBLEMS">PROBLEMS</a>
|
||||
- target-specific known issues</li>
|
||||
|
@ -63,9 +63,8 @@
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
/// pair holds two objects of arbitrary type.
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
struct pair
|
||||
{
|
||||
typedef _T1 first_type; ///< @c first_type is the first bound type
|
||||
@ -79,51 +78,51 @@ namespace std
|
||||
/** The default constructor creates @c first and @c second using their
|
||||
* respective default constructors. */
|
||||
pair()
|
||||
: first(), second() {}
|
||||
: first(), second() { }
|
||||
|
||||
/** Two objects may be passed to a @c pair constructor to be copied. */
|
||||
pair(const _T1& __a, const _T2& __b)
|
||||
: first(__a), second(__b) {}
|
||||
: first(__a), second(__b) { }
|
||||
|
||||
/** There is also a templated copy ctor for the @c pair class itself. */
|
||||
template <class _U1, class _U2>
|
||||
template<class _U1, class _U2>
|
||||
pair(const pair<_U1, _U2>& __p)
|
||||
: first(__p.first), second(__p.second) {}
|
||||
: first(__p.first), second(__p.second) { }
|
||||
};
|
||||
|
||||
/// Two pairs of the same type are equal iff their members are equal.
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
inline bool
|
||||
operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
{ return __x.first == __y.first && __x.second == __y.second; }
|
||||
|
||||
/// <http://gcc.gnu.org/onlinedocs/libstdc++/20_util/howto.html#pairlt>
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
inline bool
|
||||
operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
{ return __x.first < __y.first
|
||||
|| (!(__y.first < __x.first) && __x.second < __y.second); }
|
||||
|
||||
/// Uses @c operator== to find the result.
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
inline bool
|
||||
operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
{ return !(__x == __y); }
|
||||
|
||||
/// Uses @c operator< to find the result.
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
inline bool
|
||||
operator>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
{ return __y < __x; }
|
||||
|
||||
/// Uses @c operator< to find the result.
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
inline bool
|
||||
operator<=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
{ return !(__y < __x); }
|
||||
|
||||
/// Uses @c operator< to find the result.
|
||||
template <class _T1, class _T2>
|
||||
template<class _T1, class _T2>
|
||||
inline bool
|
||||
operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
{ return !(__x < __y); }
|
||||
@ -138,18 +137,11 @@ namespace std
|
||||
* but LWG issue #181 says they should be passed by const value. We follow
|
||||
* the LWG by default.
|
||||
*/
|
||||
template <class _T1, class _T2>
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 181. make_pair() unintended behavior
|
||||
inline pair<_T1, _T2>
|
||||
make_pair(_T1 __x, _T2 __y)
|
||||
{ return pair<_T1, _T2>(__x, __y); }
|
||||
|
||||
template<class _T1, class _T2>
|
||||
inline pair<_T1, _T2>
|
||||
make_pair(_T1 __x, _T2 __y) { return pair<_T1, _T2>(__x, __y); }
|
||||
} // namespace std
|
||||
|
||||
#endif /* _PAIR_H */
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
|
@ -39,18 +39,14 @@ GLIBCXX_DIR=${glibcxx_builddir}/src/.libs
|
||||
CXXLINK = \
|
||||
$(LIBTOOL) --tag=CXX --mode=link $(CXX) \
|
||||
-R $(GLIBGCC_DIR) -R $(GLIBCXX_DIR) \
|
||||
$(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
|
||||
|
||||
# Generated lists of files to run. All of these names are valid make
|
||||
# targets, if you wish to generate a list manually.
|
||||
lists_of_files = \
|
||||
testsuite_files \
|
||||
testsuite_files_interactive \
|
||||
testsuite_files_performance
|
||||
$(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -lv3test -L. -o $@
|
||||
|
||||
## Build support library.
|
||||
noinst_LIBRARIES = libv3test.a
|
||||
libv3test_a_SOURCES = testsuite_hooks.cc testsuite_allocator.cc
|
||||
libv3test_a_SOURCES = \
|
||||
testsuite_abi.cc \
|
||||
testsuite_allocator.cc \
|
||||
testsuite_hooks.cc
|
||||
|
||||
## Build support utilities.
|
||||
if GLIBCXX_TEST_ABI
|
||||
@ -59,6 +55,7 @@ else
|
||||
noinst_PROGRAMS =
|
||||
endif
|
||||
abi_check_SOURCES = abi_check.cc
|
||||
abi_check_DEPENDENCIES = libv3test.a
|
||||
|
||||
all-local: stamp_wchar testsuite_files
|
||||
|
||||
@ -70,6 +67,14 @@ else
|
||||
stamp_wchar:
|
||||
endif
|
||||
|
||||
# Generated lists of files to run. All of these names are valid make
|
||||
# targets, if you wish to generate a list manually.
|
||||
lists_of_files = \
|
||||
testsuite_files \
|
||||
testsuite_files_interactive \
|
||||
testsuite_files_performance
|
||||
|
||||
|
||||
# We need more things in site.exp, but automake completely controls the
|
||||
# creation of that file; there's no way to append to it without messing up
|
||||
# the dependancy chains. So we overrule automake. This rule is exactly
|
||||
|
@ -58,8 +58,8 @@ ARFLAGS = cru
|
||||
LIBRARIES = $(noinst_LIBRARIES)
|
||||
libv3test_a_AR = $(AR) $(ARFLAGS)
|
||||
libv3test_a_LIBADD =
|
||||
am_libv3test_a_OBJECTS = testsuite_hooks.$(OBJEXT) \
|
||||
testsuite_allocator.$(OBJEXT)
|
||||
am_libv3test_a_OBJECTS = testsuite_abi.$(OBJEXT) \
|
||||
testsuite_allocator.$(OBJEXT) testsuite_hooks.$(OBJEXT)
|
||||
libv3test_a_OBJECTS = $(am_libv3test_a_OBJECTS)
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am_abi_check_OBJECTS = abi_check.$(OBJEXT)
|
||||
@ -272,8 +272,16 @@ GLIBCXX_DIR = ${glibcxx_builddir}/src/.libs
|
||||
CXXLINK = \
|
||||
$(LIBTOOL) --tag=CXX --mode=link $(CXX) \
|
||||
-R $(GLIBGCC_DIR) -R $(GLIBCXX_DIR) \
|
||||
$(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
|
||||
$(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -lv3test -L. -o $@
|
||||
|
||||
noinst_LIBRARIES = libv3test.a
|
||||
libv3test_a_SOURCES = \
|
||||
testsuite_abi.cc \
|
||||
testsuite_allocator.cc \
|
||||
testsuite_hooks.cc
|
||||
|
||||
abi_check_SOURCES = abi_check.cc
|
||||
abi_check_DEPENDENCIES = libv3test.a
|
||||
|
||||
# Generated lists of files to run. All of these names are valid make
|
||||
# targets, if you wish to generate a list manually.
|
||||
@ -282,9 +290,6 @@ lists_of_files = \
|
||||
testsuite_files_interactive \
|
||||
testsuite_files_performance
|
||||
|
||||
noinst_LIBRARIES = libv3test.a
|
||||
libv3test_a_SOURCES = testsuite_hooks.cc testsuite_allocator.cc
|
||||
abi_check_SOURCES = abi_check.cc
|
||||
baseline_file = ${baseline_dir}/baseline_symbols.txt
|
||||
extract_symvers = $(glibcxx_srcdir)/scripts/extract_symvers
|
||||
|
||||
|
@ -1,311 +1,38 @@
|
||||
// Utility for libstdc++ ABI analysis -*- C++ -*-
|
||||
// -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library 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.
|
||||
// Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
// This library 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.
|
||||
// This library 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.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING. If not, write to the Free
|
||||
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
// USA.
|
||||
// This library 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this library; see the file COPYING. If not, write to
|
||||
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
|
||||
// MA 02111-1307, USA.
|
||||
|
||||
// As a special exception, you may use this file as part of a free
|
||||
// software library without restriction. Specifically, if other files
|
||||
// instantiate templates or use macros or inline functions from this
|
||||
// file, or you compile this file and link it with other files to
|
||||
// produce an executable, this file does not by itself cause the
|
||||
// resulting executable to be covered by the GNU General Public
|
||||
// License. This exception does not however invalidate any other
|
||||
// reasons why the executable file might be covered by the GNU General
|
||||
// Public License.
|
||||
|
||||
// Benjamin Kosnik <bkoz@redhat.com>
|
||||
// Blame subsequent hacks on Loren J. Rittle <ljrittle@acm.org>, Phil
|
||||
// Edwards <pme@gcc.gnu.org>, and a cast of dozens at libstdc++@gcc.gnu.org.
|
||||
|
||||
#include <string>
|
||||
#include <ext/hash_map>
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include "testsuite_abi.h"
|
||||
#include <iostream>
|
||||
#include <cxxabi.h>
|
||||
#include <stdlib.h> // for system(3)
|
||||
#include <unistd.h> // for access(2)
|
||||
|
||||
struct symbol_info
|
||||
{
|
||||
enum category { none, function, object, error };
|
||||
category type;
|
||||
std::string name;
|
||||
std::string demangled_name;
|
||||
int size;
|
||||
std::string version_name;
|
||||
|
||||
symbol_info() : type(none), size(0) { }
|
||||
|
||||
symbol_info(const symbol_info& other)
|
||||
: type(other.type), name(other.name), demangled_name(other.demangled_name),
|
||||
size(other.size), version_name(other.version_name) { }
|
||||
};
|
||||
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
template<>
|
||||
struct hash<string>
|
||||
{
|
||||
size_t operator()(const string& s) const
|
||||
{
|
||||
const collate<char>& c = use_facet<collate<char> >(locale::classic());
|
||||
return c.hash(s.c_str(), s.c_str() + s.size());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
typedef std::deque<std::string> symbol_names;
|
||||
typedef __gnu_cxx::hash_map<std::string, symbol_info> symbol_infos;
|
||||
|
||||
|
||||
bool
|
||||
check_version(const symbol_info& test, bool added = false)
|
||||
{
|
||||
typedef std::vector<std::string> compat_list;
|
||||
static compat_list known_versions;
|
||||
if (known_versions.empty())
|
||||
{
|
||||
known_versions.push_back("GLIBCPP_3.2"); // base version
|
||||
known_versions.push_back("GLIBCPP_3.2.1");
|
||||
known_versions.push_back("GLIBCPP_3.2.2");
|
||||
known_versions.push_back("GLIBCPP_3.2.3"); // gcc-3.3.0
|
||||
known_versions.push_back("GLIBCXX_3.4");
|
||||
known_versions.push_back("CXXABI_1.2");
|
||||
known_versions.push_back("CXXABI_1.2.1");
|
||||
known_versions.push_back("CXXABI_1.3");
|
||||
}
|
||||
compat_list::iterator begin = known_versions.begin();
|
||||
compat_list::iterator end = known_versions.end();
|
||||
|
||||
// Check version names for compatibility...
|
||||
compat_list::iterator it1 = find(begin, end, test.version_name);
|
||||
|
||||
// Check for weak label.
|
||||
compat_list::iterator it2 = find(begin, end, test.name);
|
||||
|
||||
// Check that added symbols aren't added in the base version.
|
||||
bool compat = true;
|
||||
if (added && test.version_name == known_versions[0])
|
||||
compat = false;
|
||||
|
||||
if (it1 == end && it2 == end)
|
||||
compat = false;
|
||||
|
||||
return compat;
|
||||
}
|
||||
|
||||
bool
|
||||
check_compatible(const symbol_info& lhs, const symbol_info& rhs,
|
||||
bool verbose = false)
|
||||
{
|
||||
using namespace std;
|
||||
bool ret = true;
|
||||
const char tab = '\t';
|
||||
|
||||
// Check to see if symbol_infos are compatible.
|
||||
if (lhs.type != rhs.type)
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
{
|
||||
cout << tab << "incompatible types" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (lhs.name != rhs.name)
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
{
|
||||
cout << tab << "incompatible names" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (lhs.size != rhs.size)
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
{
|
||||
cout << tab << "incompatible sizes" << endl;
|
||||
cout << tab << lhs.size << endl;
|
||||
cout << tab << rhs.size << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (lhs.version_name != rhs.version_name
|
||||
&& !check_version(lhs) && !check_version(rhs))
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
{
|
||||
cout << tab << "incompatible versions" << endl;
|
||||
cout << tab << lhs.version_name << endl;
|
||||
cout << tab << rhs.version_name << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
cout << endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char*
|
||||
demangle(const std::string& mangled)
|
||||
{
|
||||
const char* name;
|
||||
if (mangled[0] != '_' || mangled[1] != 'Z')
|
||||
{
|
||||
// This is not a mangled symbol, thus has "C" linkage.
|
||||
name = mangled.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use __cxa_demangle to demangle.
|
||||
int status = 0;
|
||||
name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
|
||||
if (!name)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case 0:
|
||||
name = "error code = 0: success";
|
||||
break;
|
||||
case -1:
|
||||
name = "error code = -1: memory allocation failure";
|
||||
break;
|
||||
case -2:
|
||||
name = "error code = -2: invalid mangled name";
|
||||
break;
|
||||
case -3:
|
||||
name = "error code = -3: invalid arguments";
|
||||
break;
|
||||
default:
|
||||
name = "error code unknown - who knows what happened";
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
line_to_symbol_info(std::string& input, symbol_info& output)
|
||||
{
|
||||
using namespace std;
|
||||
const char delim = ':';
|
||||
const char version_delim = '@';
|
||||
const string::size_type npos = string::npos;
|
||||
string::size_type n = 0;
|
||||
|
||||
// Set the type.
|
||||
if (input.find("FUNC") == 0)
|
||||
output.type = symbol_info::function;
|
||||
else if (input.find("OBJECT") == 0)
|
||||
output.type = symbol_info::object;
|
||||
else
|
||||
output.type = symbol_info::error;
|
||||
n = input.find_first_of(delim);
|
||||
if (n != npos)
|
||||
input.erase(input.begin(), input.begin() + n + 1);
|
||||
|
||||
// Iff object, get size info.
|
||||
if (output.type == symbol_info::object)
|
||||
{
|
||||
n = input.find_first_of(delim);
|
||||
if (n != npos)
|
||||
{
|
||||
string size(input.begin(), input.begin() + n);
|
||||
istringstream iss(size);
|
||||
int x;
|
||||
iss >> x;
|
||||
if (!iss.fail())
|
||||
output.size = x;
|
||||
input.erase(input.begin(), input.begin() + n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the name.
|
||||
n = input.find_first_of(version_delim);
|
||||
if (n != npos)
|
||||
{
|
||||
// Found version string.
|
||||
output.name = string(input.begin(), input.begin() + n);
|
||||
n = input.find_last_of(version_delim);
|
||||
input.erase(input.begin(), input.begin() + n + 1);
|
||||
|
||||
// Set version name.
|
||||
output.version_name = input;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No versioning info.
|
||||
output.name = string(input.begin(), input.end());
|
||||
input.erase(input.begin(), input.end());
|
||||
}
|
||||
|
||||
// Set the demangled name.
|
||||
output.demangled_name = demangle(output.name);
|
||||
}
|
||||
|
||||
void
|
||||
create_symbol_data(const char* file, symbol_infos& symbols,
|
||||
symbol_names& names)
|
||||
{
|
||||
// Parse list of symbols in file into vectors of symbol_info.
|
||||
// For 3.2.0 on x86/linux, this usually is
|
||||
// 947 non-weak symbols
|
||||
// 2084 weak symbols
|
||||
using namespace std;
|
||||
ifstream ifs(file);
|
||||
if (ifs.is_open())
|
||||
{
|
||||
// Organize input into container of symbol_info objects.
|
||||
const string empty;
|
||||
string line = empty;
|
||||
while (getline(ifs, line).good())
|
||||
{
|
||||
symbol_info symbol;
|
||||
line_to_symbol_info(line, symbol);
|
||||
symbols[symbol.name] = symbol;
|
||||
names.push_back(symbol.name);
|
||||
line = empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
report_symbol_info(const symbol_info& symbol, std::size_t n, bool ret = true)
|
||||
{
|
||||
using namespace std;
|
||||
const char tab = '\t';
|
||||
|
||||
// Add any other information to display here.
|
||||
cout << tab << symbol.demangled_name << endl;
|
||||
cout << tab << symbol.name << endl;
|
||||
cout << tab << symbol.version_name << endl;
|
||||
|
||||
if (ret)
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
@ -313,144 +40,54 @@ main(int argc, char** argv)
|
||||
using namespace std;
|
||||
|
||||
// Get arguments. (Heading towards getopt_long, I can feel it.)
|
||||
bool verbose = false;
|
||||
string argv1 = argc > 1 ? argv[1] : "";
|
||||
if (argv1 == "--help" || argc < 4)
|
||||
{
|
||||
cerr << "usage: abi_check --check current baseline\n"
|
||||
" --check-verbose current baseline\n"
|
||||
" --help\n\n"
|
||||
"Where CURRENT is a file containing the current results from\n"
|
||||
"extract_symvers, and BASELINE is one from config/abi.\n"
|
||||
" --examine symbol current\n"
|
||||
" --help\n"
|
||||
"\n"
|
||||
"All arguments are string literals.\n"
|
||||
"CURRENT is a file generated byextract_symvers.\n"
|
||||
"BASELINE is a file from config/abi.\n"
|
||||
"SYMBOL is a mangled name.\n"
|
||||
<< endl;
|
||||
exit(1);
|
||||
}
|
||||
else if (argv1 == "--check-verbose")
|
||||
verbose = true;
|
||||
|
||||
// Quick sanity/setup check for arguments.
|
||||
const char* test_file = argv[2];
|
||||
const char* baseline_file = argv[3];
|
||||
if (access(test_file, R_OK) != 0)
|
||||
|
||||
if (argv1.find("--check") != string::npos)
|
||||
{
|
||||
cerr << "Cannot read symbols file " << test_file
|
||||
<< ", did you forget to build first?" << endl;
|
||||
exit(1);
|
||||
}
|
||||
if (access(baseline_file, R_OK) != 0)
|
||||
{
|
||||
cerr << "Cannot read baseline file " << baseline_file << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Input both lists of symbols into container.
|
||||
symbol_infos baseline_symbols;
|
||||
symbol_names baseline_names;
|
||||
symbol_infos test_symbols;
|
||||
symbol_names test_names;
|
||||
create_symbol_data(baseline_file, baseline_symbols, baseline_names);
|
||||
create_symbol_data(test_file, test_symbols, test_names);
|
||||
|
||||
// Sanity check results.
|
||||
const symbol_names::size_type baseline_size = baseline_names.size();
|
||||
const symbol_names::size_type test_size = test_names.size();
|
||||
if (!baseline_size || !test_size)
|
||||
{
|
||||
cerr << "Problems parsing the list of exported symbols." << endl;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Sort out names.
|
||||
// Assuming baseline_names, test_names are both unique w/ no duplicates.
|
||||
//
|
||||
// The names added to missing_names are baseline_names not found in
|
||||
// test_names
|
||||
// -> symbols that have been deleted.
|
||||
//
|
||||
// The names added to added_names are test_names are names not in
|
||||
// baseline_names
|
||||
// -> symbols that have been added.
|
||||
symbol_names shared_names;
|
||||
symbol_names missing_names;
|
||||
symbol_names added_names = test_names;
|
||||
for (size_t i = 0; i < baseline_size; ++i)
|
||||
{
|
||||
string what(baseline_names[i]);
|
||||
symbol_names::iterator end = added_names.end();
|
||||
symbol_names::iterator it = find(added_names.begin(), end, what);
|
||||
if (it != end)
|
||||
bool verbose = false;
|
||||
if (argv1 == "--check-verbose")
|
||||
verbose = true;
|
||||
|
||||
// Quick sanity/setup check for arguments.
|
||||
const char* test_file = argv[2];
|
||||
const char* baseline_file = argv[3];
|
||||
if (access(test_file, R_OK) != 0)
|
||||
{
|
||||
// Found.
|
||||
shared_names.push_back(what);
|
||||
added_names.erase(it);
|
||||
cerr << "Cannot read symbols file " << test_file
|
||||
<< ", did you forget to build first?" << endl;
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
missing_names.push_back(what);
|
||||
}
|
||||
|
||||
// Check missing names for compatibility.
|
||||
typedef pair<symbol_info, symbol_info> symbol_pair;
|
||||
vector<symbol_pair> incompatible;
|
||||
for (size_t i = 0; i < missing_names.size(); ++i)
|
||||
{
|
||||
symbol_info base = baseline_symbols[missing_names[i]];
|
||||
incompatible.push_back(symbol_pair(base, base));
|
||||
}
|
||||
|
||||
// Check shared names for compatibility.
|
||||
for (size_t i = 0; i < shared_names.size(); ++i)
|
||||
{
|
||||
symbol_info base = baseline_symbols[shared_names[i]];
|
||||
symbol_info test = test_symbols[shared_names[i]];
|
||||
if (!check_compatible(base, test))
|
||||
incompatible.push_back(symbol_pair(base, test));
|
||||
}
|
||||
|
||||
// Check added names for compatibility.
|
||||
for (size_t i = 0; i < added_names.size(); ++i)
|
||||
{
|
||||
symbol_info test = test_symbols[added_names[i]];
|
||||
if (!check_version(test, true))
|
||||
incompatible.push_back(symbol_pair(test, test));
|
||||
}
|
||||
|
||||
// Report results.
|
||||
if (verbose && added_names.size())
|
||||
{
|
||||
cout << added_names.size() << " added symbols " << endl;
|
||||
for (size_t j = 0; j < added_names.size() ; ++j)
|
||||
report_symbol_info(test_symbols[added_names[j]], j + 1);
|
||||
}
|
||||
|
||||
if (verbose && missing_names.size())
|
||||
{
|
||||
cout << missing_names.size() << " missing symbols " << endl;
|
||||
for (size_t j = 0; j < missing_names.size() ; ++j)
|
||||
report_symbol_info(baseline_symbols[missing_names[j]], j + 1);
|
||||
}
|
||||
|
||||
if (verbose && incompatible.size())
|
||||
{
|
||||
cout << incompatible.size() << " incompatible symbols " << endl;
|
||||
for (size_t j = 0; j < incompatible.size() ; ++j)
|
||||
if (access(baseline_file, R_OK) != 0)
|
||||
{
|
||||
// First, report name.
|
||||
const symbol_info& base = incompatible[j].first;
|
||||
const symbol_info& test = incompatible[j].second;
|
||||
report_symbol_info(test, j + 1, false);
|
||||
|
||||
// Second, report reason or reasons incompatible.
|
||||
check_compatible(base, test, true);
|
||||
cerr << "Cannot read baseline file " << baseline_file << endl;
|
||||
exit(1);
|
||||
}
|
||||
compare_symbols(baseline_file, test_file, verbose);
|
||||
}
|
||||
|
||||
cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl;
|
||||
cout << endl;
|
||||
cout << "# of added symbols:\t\t " << added_names.size() << endl;
|
||||
cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
|
||||
cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
|
||||
cout << endl;
|
||||
cout << "using: " << baseline_file << endl;
|
||||
|
||||
if (argv1 == "--examine")
|
||||
{
|
||||
const char* file = argv[3];
|
||||
if (access(file, R_OK) != 0)
|
||||
{
|
||||
cerr << "Cannot read symbol file " << file << endl;
|
||||
exit(1);
|
||||
}
|
||||
examine_symbol(argv[2], file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
462
libstdc++-v3/testsuite/testsuite_abi.cc
Normal file
462
libstdc++-v3/testsuite/testsuite_abi.cc
Normal file
@ -0,0 +1,462 @@
|
||||
// -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
// This library 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 library 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 library; see the file COPYING. If not, write to
|
||||
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
|
||||
// MA 02111-1307, USA.
|
||||
|
||||
// As a special exception, you may use this file as part of a free
|
||||
// software library without restriction. Specifically, if other files
|
||||
// instantiate templates or use macros or inline functions from this
|
||||
// file, or you compile this file and link it with other files to
|
||||
// produce an executable, this file does not by itself cause the
|
||||
// resulting executable to be covered by the GNU General Public
|
||||
// License. This exception does not however invalidate any other
|
||||
// reasons why the executable file might be covered by the GNU General
|
||||
// Public License.
|
||||
|
||||
// Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
#include "testsuite_abi.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
symbol::init(string& data)
|
||||
{
|
||||
const char delim = ':';
|
||||
const char version_delim = '@';
|
||||
const string::size_type npos = string::npos;
|
||||
string::size_type n = 0;
|
||||
|
||||
// Set the type.
|
||||
if (data.find("FUNC") == 0)
|
||||
type = symbol::function;
|
||||
else if (data.find("OBJECT") == 0)
|
||||
type = symbol::object;
|
||||
else
|
||||
type = symbol::error;
|
||||
n = data.find_first_of(delim);
|
||||
if (n != npos)
|
||||
data.erase(data.begin(), data.begin() + n + 1);
|
||||
|
||||
// Iff object, get size info.
|
||||
if (type == symbol::object)
|
||||
{
|
||||
n = data.find_first_of(delim);
|
||||
if (n != npos)
|
||||
{
|
||||
string size(data.begin(), data.begin() + n);
|
||||
istringstream iss(size);
|
||||
int x;
|
||||
iss >> x;
|
||||
if (!iss.fail())
|
||||
size = x;
|
||||
data.erase(data.begin(), data.begin() + n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the name.
|
||||
n = data.find_first_of(version_delim);
|
||||
if (n != npos)
|
||||
{
|
||||
// Found version string.
|
||||
name = string(data.begin(), data.begin() + n);
|
||||
n = data.find_last_of(version_delim);
|
||||
data.erase(data.begin(), data.begin() + n + 1);
|
||||
|
||||
// Set version name.
|
||||
version_name = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No versioning info.
|
||||
name = string(data.begin(), data.end());
|
||||
data.erase(data.begin(), data.end());
|
||||
}
|
||||
|
||||
// Set the demangled name.
|
||||
demangled_name = demangle(name);
|
||||
}
|
||||
|
||||
void
|
||||
symbol::print() const
|
||||
{
|
||||
const char tab = '\t';
|
||||
cout << tab << name << endl;
|
||||
cout << tab << demangled_name << endl;
|
||||
cout << tab << version_name << endl;
|
||||
|
||||
string type_string;
|
||||
switch (type)
|
||||
{
|
||||
case none:
|
||||
type_string = "none";
|
||||
break;
|
||||
case function:
|
||||
type_string = "function";
|
||||
break;
|
||||
case object:
|
||||
type_string = "object";
|
||||
break;
|
||||
case error:
|
||||
type_string = "error";
|
||||
break;
|
||||
default:
|
||||
type_string = "<default>";
|
||||
}
|
||||
cout << tab << type_string << endl;
|
||||
|
||||
if (type == object)
|
||||
cout << tab << size << endl;
|
||||
|
||||
string status_string;
|
||||
switch (status)
|
||||
{
|
||||
case unknown:
|
||||
status_string = "unknown";
|
||||
break;
|
||||
case added:
|
||||
status_string = "added";
|
||||
break;
|
||||
case subtracted:
|
||||
status_string = "subtracted";
|
||||
break;
|
||||
case compatible:
|
||||
status_string = "compatible";
|
||||
break;
|
||||
case incompatible:
|
||||
status_string = "incompatible";
|
||||
break;
|
||||
default:
|
||||
status_string = "<default>";
|
||||
}
|
||||
cout << tab << status_string << endl;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
check_version(const symbol& test, bool added)
|
||||
{
|
||||
typedef std::vector<std::string> compat_list;
|
||||
static compat_list known_versions;
|
||||
if (known_versions.empty())
|
||||
{
|
||||
known_versions.push_back("GLIBCPP_3.2"); // base version
|
||||
known_versions.push_back("GLIBCPP_3.2.1");
|
||||
known_versions.push_back("GLIBCPP_3.2.2");
|
||||
known_versions.push_back("GLIBCPP_3.2.3"); // gcc-3.3.0
|
||||
known_versions.push_back("GLIBCXX_3.4");
|
||||
known_versions.push_back("CXXABI_1.2");
|
||||
known_versions.push_back("CXXABI_1.2.1");
|
||||
known_versions.push_back("CXXABI_1.3");
|
||||
}
|
||||
compat_list::iterator begin = known_versions.begin();
|
||||
compat_list::iterator end = known_versions.end();
|
||||
|
||||
// Check version names for compatibility...
|
||||
compat_list::iterator it1 = find(begin, end, test.version_name);
|
||||
|
||||
// Check for weak label.
|
||||
compat_list::iterator it2 = find(begin, end, test.name);
|
||||
|
||||
// Check that added symbols aren't added in the base version.
|
||||
bool compat = true;
|
||||
if (added && test.version_name == known_versions[0])
|
||||
compat = false;
|
||||
|
||||
if (it1 == end && it2 == end)
|
||||
compat = false;
|
||||
|
||||
return compat;
|
||||
}
|
||||
|
||||
bool
|
||||
check_compatible(const symbol& lhs, const symbol& rhs, bool verbose)
|
||||
{
|
||||
bool ret = true;
|
||||
const char tab = '\t';
|
||||
|
||||
// Check to see if symbol_objects are compatible.
|
||||
if (lhs.type != rhs.type)
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
cout << tab << "incompatible types" << endl;
|
||||
}
|
||||
|
||||
if (lhs.name != rhs.name)
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
cout << tab << "incompatible names" << endl;
|
||||
}
|
||||
|
||||
if (lhs.size != rhs.size)
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
{
|
||||
cout << tab << "incompatible sizes" << endl;
|
||||
cout << tab << lhs.size << endl;
|
||||
cout << tab << rhs.size << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (lhs.version_name != rhs.version_name
|
||||
&& !check_version(lhs) && !check_version(rhs))
|
||||
{
|
||||
ret = false;
|
||||
if (verbose)
|
||||
{
|
||||
cout << tab << "incompatible versions" << endl;
|
||||
cout << tab << lhs.version_name << endl;
|
||||
cout << tab << rhs.version_name << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
cout << endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
has_symbol(const string& mangled, const symbols& s) throw()
|
||||
{
|
||||
const symbol_names& names = s.first;
|
||||
symbol_names::const_iterator i = find(names.begin(), names.end(), mangled);
|
||||
return i != names.end();
|
||||
}
|
||||
|
||||
symbol&
|
||||
get_symbol(const string& mangled, const symbols& s)
|
||||
{
|
||||
const symbol_names& names = s.first;
|
||||
symbol_names::const_iterator i = find(names.begin(), names.end(), mangled);
|
||||
if (i != names.end())
|
||||
{
|
||||
symbol_objects objects = s.second;
|
||||
return objects[mangled];
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream os;
|
||||
os << "get_symbol failed for symbol " << mangled;
|
||||
throw symbol_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
examine_symbol(const char* name, const char* file)
|
||||
{
|
||||
try
|
||||
{
|
||||
symbols s = create_symbols(file);
|
||||
symbol& sym = get_symbol(name, s);
|
||||
sym.print();
|
||||
}
|
||||
catch(...)
|
||||
{ throw; }
|
||||
}
|
||||
|
||||
void
|
||||
compare_symbols(const char* baseline_file, const char* test_file,
|
||||
bool verbose)
|
||||
{
|
||||
// Input both lists of symbols into container.
|
||||
symbols baseline = create_symbols(baseline_file);
|
||||
symbols test = create_symbols(test_file);
|
||||
symbol_names& baseline_names = baseline.first;
|
||||
symbol_objects& baseline_objects = baseline.second;
|
||||
symbol_names& test_names = test.first;
|
||||
symbol_objects& test_objects = test.second;
|
||||
|
||||
// Sanity check results.
|
||||
const symbol_names::size_type baseline_size = baseline_names.size();
|
||||
const symbol_names::size_type test_size = test_names.size();
|
||||
if (!baseline_size || !test_size)
|
||||
{
|
||||
cerr << "Problems parsing the list of exported symbols." << endl;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Sort out names.
|
||||
// Assuming baseline_names, test_names are both unique w/ no duplicates.
|
||||
//
|
||||
// The names added to missing_names are baseline_names not found in
|
||||
// test_names
|
||||
// -> symbols that have been deleted.
|
||||
//
|
||||
// The names added to added_names are test_names are names not in
|
||||
// baseline_names
|
||||
// -> symbols that have been added.
|
||||
symbol_names shared_names;
|
||||
symbol_names missing_names;
|
||||
symbol_names added_names = test_names;
|
||||
for (size_t i = 0; i < baseline_size; ++i)
|
||||
{
|
||||
string what(baseline_names[i]);
|
||||
symbol_names::iterator end = added_names.end();
|
||||
symbol_names::iterator it = find(added_names.begin(), end, what);
|
||||
if (it != end)
|
||||
{
|
||||
// Found.
|
||||
shared_names.push_back(what);
|
||||
added_names.erase(it);
|
||||
}
|
||||
else
|
||||
missing_names.push_back(what);
|
||||
}
|
||||
|
||||
// Check missing names for compatibility.
|
||||
typedef pair<symbol, symbol> symbol_pair;
|
||||
vector<symbol_pair> incompatible;
|
||||
for (size_t i = 0; i < missing_names.size(); ++i)
|
||||
{
|
||||
symbol base = baseline_objects[missing_names[i]];
|
||||
incompatible.push_back(symbol_pair(base, base));
|
||||
}
|
||||
|
||||
// Check shared names for compatibility.
|
||||
for (size_t i = 0; i < shared_names.size(); ++i)
|
||||
{
|
||||
symbol base = baseline_objects[shared_names[i]];
|
||||
symbol test = test_objects[shared_names[i]];
|
||||
if (!check_compatible(base, test))
|
||||
incompatible.push_back(symbol_pair(base, test));
|
||||
}
|
||||
|
||||
// Check added names for compatibility.
|
||||
for (size_t i = 0; i < added_names.size(); ++i)
|
||||
{
|
||||
symbol test = test_objects[added_names[i]];
|
||||
if (!check_version(test, true))
|
||||
incompatible.push_back(symbol_pair(test, test));
|
||||
}
|
||||
|
||||
// Report results.
|
||||
if (verbose && added_names.size())
|
||||
{
|
||||
cout << added_names.size() << " added symbols " << endl;
|
||||
for (size_t j = 0; j < added_names.size() ; ++j)
|
||||
test_objects[added_names[j]].print();
|
||||
}
|
||||
|
||||
if (verbose && missing_names.size())
|
||||
{
|
||||
cout << missing_names.size() << " missing symbols " << endl;
|
||||
for (size_t j = 0; j < missing_names.size() ; ++j)
|
||||
baseline_objects[missing_names[j]].print();
|
||||
}
|
||||
|
||||
if (verbose && incompatible.size())
|
||||
{
|
||||
cout << incompatible.size() << " incompatible symbols " << endl;
|
||||
for (size_t j = 0; j < incompatible.size() ; ++j)
|
||||
{
|
||||
// First, report name.
|
||||
const symbol& base = incompatible[j].first;
|
||||
const symbol& test = incompatible[j].second;
|
||||
test.print();
|
||||
|
||||
// Second, report reason or reasons incompatible.
|
||||
check_compatible(base, test, true);
|
||||
}
|
||||
}
|
||||
|
||||
cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl;
|
||||
cout << endl;
|
||||
cout << "# of added symbols:\t\t " << added_names.size() << endl;
|
||||
cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
|
||||
cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
|
||||
cout << endl;
|
||||
cout << "using: " << baseline_file << endl;
|
||||
}
|
||||
|
||||
|
||||
symbols
|
||||
create_symbols(const char* file)
|
||||
{
|
||||
symbols s;
|
||||
ifstream ifs(file);
|
||||
if (ifs.is_open())
|
||||
{
|
||||
// Organize file data into container of symbol objects.
|
||||
symbol_names& names = s.first;
|
||||
symbol_objects& objects = s.second;
|
||||
const string empty;
|
||||
string line = empty;
|
||||
while (getline(ifs, line).good())
|
||||
{
|
||||
symbol tmp;
|
||||
tmp.init(line);
|
||||
objects[tmp.name] = tmp;
|
||||
names.push_back(tmp.name);
|
||||
line = empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream os;
|
||||
os << "create_symbols failed for file " << file;
|
||||
throw runtime_error(os.str());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
demangle(const std::string& mangled)
|
||||
{
|
||||
const char* name;
|
||||
if (mangled[0] != '_' || mangled[1] != 'Z')
|
||||
{
|
||||
// This is not a mangled symbol, thus has "C" linkage.
|
||||
name = mangled.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use __cxa_demangle to demangle.
|
||||
int status = 0;
|
||||
name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
|
||||
if (!name)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case 0:
|
||||
name = "error code = 0: success";
|
||||
break;
|
||||
case -1:
|
||||
name = "error code = -1: memory allocation failure";
|
||||
break;
|
||||
case -2:
|
||||
name = "error code = -2: invalid mangled name";
|
||||
break;
|
||||
case -3:
|
||||
name = "error code = -3: invalid arguments";
|
||||
break;
|
||||
default:
|
||||
name = "error code unknown - who knows what happened";
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
129
libstdc++-v3/testsuite/testsuite_abi.h
Normal file
129
libstdc++-v3/testsuite/testsuite_abi.h
Normal file
@ -0,0 +1,129 @@
|
||||
// -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
// This library 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 library 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 library; see the file COPYING. If not, write to
|
||||
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
|
||||
// MA 02111-1307, USA.
|
||||
|
||||
// As a special exception, you may use this file as part of a free
|
||||
// software library without restriction. Specifically, if other files
|
||||
// instantiate templates or use macros or inline functions from this
|
||||
// file, or you compile this file and link it with other files to
|
||||
// produce an executable, this file does not by itself cause the
|
||||
// resulting executable to be covered by the GNU General Public
|
||||
// License. This exception does not however invalidate any other
|
||||
// reasons why the executable file might be covered by the GNU General
|
||||
// Public License.
|
||||
|
||||
// Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <deque>
|
||||
#include <ext/hash_map>
|
||||
#include <cxxabi.h>
|
||||
|
||||
// Encapsulates symbol characteristics.
|
||||
struct symbol
|
||||
{
|
||||
enum category { none, function, object, error };
|
||||
enum designation { unknown, added, subtracted, compatible, incompatible };
|
||||
enum compatibility
|
||||
{
|
||||
compat_type = 1,
|
||||
compat_name = 2,
|
||||
compat_size = 4,
|
||||
compat_version = 8
|
||||
};
|
||||
|
||||
category type;
|
||||
std::string name;
|
||||
std::string demangled_name;
|
||||
int size;
|
||||
std::string version_name;
|
||||
designation status;
|
||||
|
||||
symbol() : type(none), size(0), status(unknown) { }
|
||||
|
||||
symbol(const symbol& other)
|
||||
: type(other.type), name(other.name), demangled_name(other.demangled_name),
|
||||
size(other.size), version_name(other.version_name),
|
||||
status(other.status) { }
|
||||
|
||||
void
|
||||
print() const;
|
||||
|
||||
void
|
||||
init(std::string& data);
|
||||
};
|
||||
|
||||
struct symbol_error : public std::logic_error
|
||||
{
|
||||
explicit symbol_error(const std::string& s) : std::logic_error(s) { }
|
||||
};
|
||||
|
||||
|
||||
typedef __gnu_cxx::hash_map<std::string, symbol> symbol_objects;
|
||||
|
||||
typedef std::deque<std::string> symbol_names;
|
||||
|
||||
typedef std::pair<symbol_names, symbol_objects> symbols;
|
||||
|
||||
|
||||
// Check.
|
||||
bool
|
||||
check_version(const symbol& test, bool added = false);
|
||||
|
||||
bool
|
||||
check_compatible(const symbol& lhs, const symbol& rhs, bool verbose = false);
|
||||
|
||||
|
||||
// Examine.
|
||||
bool
|
||||
has_symbol(const std::string& mangled, const symbols& list) throw();
|
||||
|
||||
symbol&
|
||||
get_symbol(const std::string& mangled, const symbols& list);
|
||||
|
||||
extern "C" void
|
||||
examine_symbol(const char* name, const char* file);
|
||||
|
||||
extern "C" void
|
||||
compare_symbols(const char* baseline_file, const char* test_file, bool verb);
|
||||
|
||||
|
||||
// Util.
|
||||
symbols
|
||||
create_symbols(const char* file);
|
||||
|
||||
const char*
|
||||
demangle(const std::string& mangled);
|
||||
|
||||
|
||||
// Specialization.
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
template<>
|
||||
struct hash<string>
|
||||
{
|
||||
size_t operator()(const string& s) const
|
||||
{
|
||||
const collate<char>& c = use_facet<collate<char> >(locale::classic());
|
||||
return c.hash(s.c_str(), s.c_str() + s.size());
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user