From: Benjamin Kosnik Date: Thu, 13 May 2004 12:50:53 +0000 (+0000) Subject: abi.html: New. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4b260c20138daad0b7507cdd555025bb84bf2000;p=gcc.git abi.html: New. 2004-05-13 Benjamin Kosnik * 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 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 6d723b422d9..428c55940a8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2004-05-13 Benjamin Kosnik + + * 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 * include/backward/iterator.h: Add GPL copyright info, diff --git a/libstdc++-v3/docs/html/17_intro/TODO b/libstdc++-v3/docs/html/17_intro/TODO index 1670f042e28..93685fa3c9e 100644 --- a/libstdc++-v3/docs/html/17_intro/TODO +++ b/libstdc++-v3/docs/html/17_intro/TODO @@ -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: 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 diff --git a/libstdc++-v3/docs/html/abi.html b/libstdc++-v3/docs/html/abi.html new file mode 100644 index 00000000000..fcb84e91793 --- /dev/null +++ b/libstdc++-v3/docs/html/abi.html @@ -0,0 +1,857 @@ + + + + + + + + + + Standard C++ Library ABI + + + + + + +

C++ Standard Library ABI

+ +

+ The latest version of this document is always available at + + http://gcc.gnu.org/onlinedocs/libstdc++/abi.html. +

+ +

+ To the libstdc++-v3 homepage. +

+ + +
+

+ The C++ interface +

+ +

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. +

+ +

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. +

+ +

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 + ABI specification. +

+ +

+ 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 -fabi-version. In addition, some + g++ command line options may change the ABI as a side-effect of + use. Such flags include -fpack-struct and + -fno-exceptions, but include others: see the complete + list in the GCC manual under the heading Options + for Code Generation Conventions. +

+ +

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 + +here. +

+ +

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: +

+ + library API + compiler ABI = library ABI + +

+ 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. +

+ +

+ 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. +

+ +

+ Versioning +

+ +

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. +

+ +
+ Goals of versioning +
+ +

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. +

+ +

Allows multiple, incompatible ABIs to coexist at the same time. +

+ +

+

+ +
+ Version History +
+

+ 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. This is +implemented via file names and the ELF DT_SONAME mechanism (at least +on ELF systems).

    + +

    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
    • +
    • gcc-3.2.1: libgcc_s.so.1
    • +
    • gcc-3.2.2: libgcc_s.so.1
    • +
    • gcc-3.2.3: libgcc_s.so.1
    • +
    • gcc-3.3.0: libgcc_s.so.1
    • +
    • gcc-3.3.1: libgcc_s.so.1
    • +
    • gcc-3.3.2: libgcc_s.so.1
    • +
    • gcc-3.3.3: libgcc_s.so.1
    • +
    • gcc-3.4.0: libgcc_s.so.1
    • +
    +
  • +

    + +
  • Release versioning on the libstdc++.so binary, implemented in the same was as the libgcc_s.so binary, above. + +

    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
    • +
    • gcc-3.2.1: libstdc++.so.5.0.1
    • +
    • gcc-3.2.2: libstdc++.so.5.0.2
    • +
    • gcc-3.2.3: libstdc++.so.5.0.3 (Not strictly required)
    • +
    • gcc-3.3.0: libstdc++.so.5.0.4
    • +
    • gcc-3.3.1: libstdc++.so.5.0.5
    • +
    • gcc-3.3.2: libstdc++.so.5.0.5
    • +
    • gcc-3.3.3: libstdc++.so.5.0.5
    • +
    • gcc-3.4.0: libstdc++.so.6.0.0
    • +
    +
  • +

    + +
  • Symbol versioning on the libgcc_s.so binary. +

    mapfile: gcc/libgcc-std.ver

    + +

    It is versioned with the following labels and version definitions:

    +
      +
    • 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
    • +
    • gcc-3.2.1: GCC_3.0
    • +
    • gcc-3.2.2: GCC_3.0
    • +
    • gcc-3.2.3: GCC_3.0
    • +
    • gcc-3.3.0: GCC_3.0
    • +
    • gcc-3.3.1: GCC_3.0
    • +
    • gcc-3.3.2: GCC_3.0
    • +
    • gcc-3.3.3: GCC_3.0
    • +
    • gcc-3.4.0: GCC_3.0
    • +
    +
  • +

    + +
  • Symbol versioning on the libstdc++.so binary. + +

    mapfile: libstdc++-v3/config/linker-map.gnu

    +

    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.) +

    +
      +
    • gcc-3.0.0: (Error, not versioned)
    • +
    • gcc-3.0.1: (Error, not versioned)
    • +
    • gcc-3.0.2: (Error, not versioned)
    • +
    • gcc-3.0.3: (Error, not versioned)
    • +
    • gcc-3.0.4: (Error, not versioned)
    • +
    • 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
    • +
    • gcc-3.2.1: GLIBCPP_3.2.1, CXXABI_1.2
    • +
    • gcc-3.2.2: GLIBCPP_3.2.2, CXXABI_1.2
    • +
    • gcc-3.2.3: GLIBCPP_3.2.2, CXXABI_1.2
    • +
    • gcc-3.3.0: GLIBCPP_3.2.2, CXXABI_1.2.1
    • +
    • gcc-3.3.1: GLIBCPP_3.2.3, CXXABI_1.2.1
    • +
    • gcc-3.3.2: GLIBCPP_3.2.3, CXXABI_1.2.1
    • +
    • gcc-3.3.3: GLIBCPP_3.2.3, CXXABI_1.2.1
    • +
    • gcc-3.4.0: GLIBCXX_3.4, CXXABI_1.3
    • +
    +
  • +

    + +
  • +

    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
    • +
    • gcc-3.3.x: 102
    • +
    • gcc-3.4.x: 1002
    • +
    +
  • +

    + +
  • +

    Changes to the default compiler option for + -fabi-version. +

    +

    + It is versioned as follows: +

    +
      +
    • gcc-3.0.x: (Error, not versioned)
    • +
    • gcc-3.1.x: (Error, not versioned)
    • +
    • gcc-3.2.x: -fabi-version=1
    • +
    • gcc-3.3.x: -fabi-version=1
    • +
    • gcc-3.4.x: -fabi-version=2
    • +
    +
  • +

    + +
  • +

    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. +

    + +

    + 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. +

    +

    + 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
    • +
    • gcc-3.2.1: 20021119
    • +
    • gcc-3.2.2: 20030205
    • +
    • gcc-3.2.3: 20030422
    • +
    • gcc-3.3.0: 20030513
    • +
    • gcc-3.3.1: 20030804
    • +
    • gcc-3.3.2: 20031016
    • +
    • gcc-3.3.3: 20040214
    • +
    • gcc-3.4.0: 20040419
    • +
    +
  • +

    + + +
  • +

    + 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. +

    + +

    + 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"
    • +
    • gcc-3.2.1: "3.2.1"
    • +
    • gcc-3.2.2: "3.2.2"
    • +
    • gcc-3.2.3: "3.2.3"
    • +
    • gcc-3.3.0: "3.3"
    • +
    • gcc-3.3.1: "3.3.1"
    • +
    • gcc-3.3.2: "3.3.2"
    • +
    • gcc-3.3.3: "3.3.3"
    • +
    • gcc-3.4.0: "version-unused"
    • +
    +
  • +

    + +
  • +

    + 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
    • +
    • gcc-3.2.1: include/c++/3.2.1
    • +
    • gcc-3.2.2: include/c++/3.2.2
    • +
    • gcc-3.2.3: include/c++/3.2.3
    • +
    • gcc-3.3.0: include/c++/3.3
    • +
    • gcc-3.3.1: include/c++/3.3.1
    • +
    • gcc-3.3.2: include/c++/3.3.2
    • +
    • gcc-3.3.3: include/c++/3.3.3
    • +
    • gcc-3.4.0: include/c++/3.4.0
    • +
    +
  • +

    +
+

+ 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 requirements for a versioned ABI +
+

+ 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. +

+ +

+ 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 and more recent vintages, 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 to 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 and link it to the shared + libstdc++ library: +

+ +
+#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
+
+ +

+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: +

+ + U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4 + +

+ Library allowed ABI changes +

+

+The following will cause the library minor version number to +increase, say from "libstdc++.so.3.0.4" to "libstdc++.so.3.0.5". +

+
    +
  • adding an exported global or static data member
  • +
  • adding an exported function, static or non-virtual member function
  • +
  • adding an exported symbol or symbols by additional instantiations
  • +
+

+

+

+Other allowed changes are possible. +

+ + +

+ Library disallowed ABI changes +

+ +

+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". +

+
    +
  • changes in the gcc/g++ compiler ABI
  • +
  • changing size of an exported symbol
  • +
  • changing alignment of an exported symbol
  • +
  • changing the layout of an exported symbol
  • +
  • changing mangling on an exported symbol
  • +
  • deleting an exported symbol
  • +
  • changing the inheritance properties of a type by adding or removing + base classes
  • +
  • + 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. +
  • +
+ +

+ Library implementation strategy +

+ +
    +
  • Separation of interface and implementation
  • +

    This is accomplished by two techniques that separate the API from +the ABI: forcing undefined references to link against a library binary +for definitions. +

    + +
      +
    • Include files have declarations, source files have defines
    • + +

      For non-templatized types, such as much of class +locale, the appropriate standard C++ include, say +locale, can contain full declarations, while various +source files (say locale.cc, locale_init.cc, +localename.cc) contain definitions.

      + +
    • Extern template on required types
    • + +

      For parts of the standard that have an explicit list of required + instantiations, the GNU extension syntax extern template + can be used to control where template definitions + reside. By marking required instantiations as extern + template 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 char and + wchar_t instantiations, and includes + basic_string, the locale facets, and the types in + iostreams.

      + +
    +

    In addition, these techniques have the additional benefit that + they reduce binary size, which can increase runtime performance. +

    + +
  • Namespaces linking symbol definitions to export mapfiles
  • + +

    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. +

    + +

    The following namespaces are transformed by the mapfile:

    + +
      +
    • namespace std
    • +

      Defaults to exporting all symbols in label +GLIBCXX that do not begin with an underscore, ie +__test_func would not be exported by default. Select +exceptional symbols are allowed to be visible.

      + +
    • namespace __gnu_cxx
    • +

      Defaults to not exporting any symbols in label +GLIBCXX, select items are allowed to be visible.

      + +
    • namespace __gnu_internal
    • +

      Defaults to not exported, no items are allowed to be visible.

      + +
    • namespace __cxxabiv1, aliased to namespace abi
    • +

      Defaults to not exporting any symbols in label +CXXABI, select items are allowed to be visible.

      +
    +

    +

    + +
  • Freezing the API
  • +

    Disallowed changes, as above, are not made on a stable release +branch. Enforcement tends to be less strict with GNU extensions that +standard includes.

+ +

+ 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 +here. +

+ +

+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! +

+ +

+ Testing Multi-ABI binaries +

+ +

+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. +

+ +

As above, libone is constructed as follows:

+
+%$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 
+
+ +

And, libtwo is constructed as follows:

+ +
+%$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 
+
+ +

...with the resulting libraries looking like

+
+%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)
+
+
+ +

Then, the "C" compiler is used to compile a source file that uses +functions from each library.

+
+gcc test.c -g -O2 -L. -lone -ltwo /usr/lib/libstdc++.so.5 /usr/lib/libstdc++.so.6
+
+ +

+Which gives the expected: +

+
+%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)
+
+ +

+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. +

+ +

+ Bibliography / Further Reading +

+ +

+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 +

diff --git a/libstdc++-v3/docs/html/abi.txt b/libstdc++-v3/docs/html/abi.txt deleted file mode 100644 index 430108885f9..00000000000 --- a/libstdc++-v3/docs/html/abi.txt +++ /dev/null @@ -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 - -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 -here. - -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 - diff --git a/libstdc++-v3/docs/html/documentation.html b/libstdc++-v3/docs/html/documentation.html index 7819955b66b..d1aea5a926e 100644 --- a/libstdc++-v3/docs/html/documentation.html +++ b/libstdc++-v3/docs/html/documentation.html @@ -30,7 +30,7 @@
  • License - GPL v2 license terms
  • -
  • ABI Policy and Guidelines
  • +
  • ABI Policy and Guidelines
  • BUGS
  • PROBLEMS - target-specific known issues
  • diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 0bbaa24ad6e..d5146bb5943 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -63,9 +63,8 @@ namespace std { - /// pair holds two objects of arbitrary type. - template + template 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 + template 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 + template inline bool operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return __x.first == __y.first && __x.second == __y.second; } /// - template + template 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 + template inline bool operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return !(__x == __y); } /// Uses @c operator< to find the result. - template + template inline bool operator>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return __y < __x; } /// Uses @c operator< to find the result. - template + template inline bool operator<=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return !(__y < __x); } /// Uses @c operator< to find the result. - template + template 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 - // _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 + 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: diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Makefile.am index c58d008d00c..9e11ac30ae9 100644 --- a/libstdc++-v3/testsuite/Makefile.am +++ b/libstdc++-v3/testsuite/Makefile.am @@ -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 diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in index bd006066bf2..b74f2b36cdb 100644 --- a/libstdc++-v3/testsuite/Makefile.in +++ b/libstdc++-v3/testsuite/Makefile.in @@ -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 diff --git a/libstdc++-v3/testsuite/abi_check.cc b/libstdc++-v3/testsuite/abi_check.cc index 2116f7a6b30..18c8b7be9b6 100644 --- a/libstdc++-v3/testsuite/abi_check.cc +++ b/libstdc++-v3/testsuite/abi_check.cc @@ -1,311 +1,38 @@ -// Utility for libstdc++ ABI analysis -*- 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. - -// 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. +// -*- 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 // Blame subsequent hacks on Loren J. Rittle , Phil // Edwards , and a cast of dozens at libstdc++@gcc.gnu.org. - -#include -#include -#include -#include -#include + +#include "testsuite_abi.h" #include -#include -#include // for system(3) -#include // 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 - { - size_t operator()(const string& s) const - { - const collate& c = use_facet >(locale::classic()); - return c.hash(s.c_str(), s.c_str() + s.size()); - } - }; -} - -typedef std::deque symbol_names; -typedef __gnu_cxx::hash_map symbol_infos; - - -bool -check_version(const symbol_info& test, bool added = false) -{ - typedef std::vector 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) - { - 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) + + if (argv1.find("--check") != string::npos) + { + 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_pair; - vector 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 (access(baseline_file, R_OK) != 0) + { + cerr << "Cannot read baseline file " << baseline_file << endl; + exit(1); + } + compare_symbols(baseline_file, test_file, verbose); } - if (verbose && incompatible.size()) + if (argv1 == "--examine") { - cout << incompatible.size() << " incompatible symbols " << endl; - for (size_t j = 0; j < incompatible.size() ; ++j) + const char* file = argv[3]; + if (access(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 symbol file " << file << endl; + exit(1); } + examine_symbol(argv[2], file); } - - 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; - return 0; } diff --git a/libstdc++-v3/testsuite/testsuite_abi.cc b/libstdc++-v3/testsuite/testsuite_abi.cc new file mode 100644 index 00000000000..552da1bca0e --- /dev/null +++ b/libstdc++-v3/testsuite/testsuite_abi.cc @@ -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 + +#include "testsuite_abi.h" +#include +#include +#include + +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 = ""; + } + 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 = ""; + } + cout << tab << status_string << endl; +} + + +bool +check_version(const symbol& test, bool added) +{ + typedef std::vector 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_pair; + vector 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; +} + diff --git a/libstdc++-v3/testsuite/testsuite_abi.h b/libstdc++-v3/testsuite/testsuite_abi.h new file mode 100644 index 00000000000..ebacb6a46e8 --- /dev/null +++ b/libstdc++-v3/testsuite/testsuite_abi.h @@ -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 + +#include +#include +#include +#include +#include + +// 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 symbol_objects; + +typedef std::deque symbol_names; + +typedef std::pair 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 + { + size_t operator()(const string& s) const + { + const collate& c = use_facet >(locale::classic()); + return c.hash(s.c_str(), s.c_str() + s.size()); + } + }; +}