<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1//EN" "http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd"> <?xml-stylesheet type="text/xsl" href="docbook-xslt/docbook/html/docbook.xsl"?> <!-- This is written using docbook 4.1 xml. HTML is generated using the xslt-stylesheets from http://www.nwalsh.com. xsltproc is an xslt-processor included in libxslt: (http://xmlsoft.org/XSLT/ or here: ftp://ftp.gnome.org/pub/GNOME/unstable/sources/libxslt/) (it requires libxml2: http://xmlsoft.org or here: ftp://ftp.gnome.org/pub/GNOME/stable/sources/libxml/) You can find the latest version of this document here: http://gcc.gnu.org/onlinedocs/libstdc++/17_intro/porting-howto(.html|.xml) --> <!-- TODO: o remove //@label: use automatic numbering o make this work: <link linkend="sec-gtkmm-hack" endterm="sec-gtkmm-hack.title"/>. o clean up the section-numbering --> <article class = "whitepaper" id = "libstdc++-porting-howto" lang = "en"> <articleinfo> <title>Libstdc++-porting-howto</title> <author> <firstname>Felix</firstname> <surname>Natter</surname> </author> <address> <email>fnatter@gmx.net</email> </address> <revhistory> <revision> <revnumber>0.5</revnumber> <date>Thu Jun 1 13:06:50 2000</date> <authorinitials>fnatter</authorinitials> <revremark>First docbook-version.</revremark> </revision> <revision> <revnumber>0.8</revnumber> <date>Sun Jul 30 20:28:40 2000</date> <authorinitials>fnatter</authorinitials> <revremark>First released version using docbook-xml + second upload to libstdc++-page. </revremark> </revision> <revision> <revnumber>0.9</revnumber> <date>Wed Sep 6 02:59:32 2000</date> <authorinitials>fnatter</authorinitials> <revremark>5 new sections.</revremark> </revision> <revision> <revnumber>0.9.1</revnumber> <date>Sat Sep 23 14:20:15 2000</date> <authorinitials>fnatter</authorinitials> <revremark>added information about why file-descriptors are not in the standard</revremark> </revision> <revision> <revnumber>0.9.2</revnumber> <date>Tue Jun 5 20:07:49 2001</date> <authorinitials>fnatter</authorinitials> <revremark> a fix, added hint on increased portability of C-shadow-headers, added autoconf-test HAVE_CONTAINER_AT </revremark> </revision> <revision> <revnumber>0.9.3</revnumber> <date>Fri Jun 29 16:15:56 2001</date> <authorinitials>fnatter</authorinitials> <revremark> changed signature of nonstandard filebuf-constructor and update the section on filebuf::attach to point to ../ext/howto.html, added link to ../21/strings/howto.html in sec-stringstream, changed <link>-tags to have content (so that these links work), replace "user-space" by "global namespace" add note about gcc 3.0 and shadow-headers add section about ostream::form and istream::scan sec-vector-at: remove hint to modify headers fix spelling error in sec-stringstream </revremark> </revision> <revision> <revnumber>0.9.4</revnumber> <date>Mon Nov 5 17:01:04 2001</date> <authorinitials>fnatter</authorinitials> <revremark> rewrite section 1.1.3 because of gnu.gcc.help-post by Juergen Heinzl </revremark> </revision> </revhistory> <legalnotice><title>Legal Notice</title> <para> This document can be distributed under the FDL (<ulink url = "http://www.gnu.org">www.gnu.org</ulink>) </para> </legalnotice> <pubdate>Tue Jun 5 20:07:49 2001</pubdate> <abstract> <para> Some notes on porting applications from libstdc++-2.90 (or earlier versions) to libstdc++-v3. Not speaking in terms of the GNU libstdc++ implementations, this means porting from earlier versions of the C++-Standard to ISO 14882. </para> </abstract> </articleinfo> <para> In the following, when I say portable, I will refer to "portable among ISO 14882-implementations". On the other hand, if I say "backportable" or "conservative", I am talking about "compiles with older libstdc++-implementations". </para> <section id="sec-nsstd" label="1"><title>Namespace std::</title> <para> The latest C++-standard (ISO-14882) requires that the standard C++-library is defined in namespace std::. Thus, in order to use classes from the standard C++-library, you can do one of three things: <itemizedlist> <listitem><para>wrap your code in <command>namespace std { ... }</command> => This is not an option because only symbols from the standard c++-library are defined in namespace std::. </para></listitem> <listitem><para>put a kind of <emphasis>using-declaration</emphasis> in your source (either <command>using namespace std;</command> or i.e. <command>using std::string;</command>) => works well for source-files, but cannot be used in header-files. </para></listitem> <listitem><para>use a <emphasis>fully qualified name</emphasis> for each libstdc++-symbol (i.e. <command>std::string</command>, <command>std::cout</command>) => can always be used </para></listitem> </itemizedlist> </para> <para> Because there are many compilers which still use an implementation that does not have the standard C++-library in namespace <command>std::</command>, some care is required to support these as well. </para> <para> Namespace back-portability-issues are generally not a problem with g++, because versions of g++ that do not have libstdc++ in <command>std::</command> use <command>-fno-honor-std</command> (ignore <command>std::</command>, <command>:: = std::</command>) by default. That is, the responsibility for enabling or disabling <command>std::</command> is on the user; the maintainer does not have to care about it. This probably applies to some other compilers as well. </para> <para> The following sections list some possible solutions to support compilers that cannot ignore std::. </para> <section id = "sec-gtkmm-hack" label = "1.1"> <title id="sec-gtkmm-hack.title">Using <emphasis>namespace composition</emphasis> if the project uses a separate namespace</title> <para> <ulink url = "http://gtkmm.sourceforge.net">Gtk--</ulink> defines most of its classes in namespace Gtk::. Thus, it was possible to adapt Gtk-- to namespace std:: by using a C++-feature called <emphasis>namespace composition</emphasis>. This is what happens if you put a <emphasis>using</emphasis>-declaration into a namespace-definition: the imported symbol(s) gets imported into the currently active namespace(s). For example: <programlisting> namespace Gtk { using std::string; class Window { ... } } </programlisting> In this example, <command>std::string</command> gets imported into namespace Gtk::. The result is that you don't have to use <command>std::string</command> in this header, but still <command>std::string</command> does not get imported into the global namespace (::) unless the user does <command>using namespace Gtk;</command> (which is not recommended practice for Gtk--, so it is not a problem). Additionally, the <command>using</command>-declarations are wrapped in macros that are set based on autoconf-tests to either "" or i.e. <command>using std::string;</command> (depending on whether the system has libstdc++ in <command>std::</command> or not). (ideas from <email>llewelly@dbritsch.dsl.xmission.com</email>, Karl Nelson <email>kenelson@ece.ucdavis.edu</email>) </para> </section> <section id = "sec-emptyns" label = "1.2"> <title id="sec-emptyns.title">Defining an empty namespace std</title> <para> By defining an (empty) namespace <command>std::</command> before using it, you avoid getting errors on systems where no part of the library is in namespace std: <programlisting> namespace std { } using namespace std; </programlisting> </para> </section> <section id = "sec-avoidfqn" label = "1.3"> <title id="sec-avoidfqn.title">Avoid to use fully qualified names (i.e. std::string)</title> <para> If some compilers complain about <command>using std::string;</command>, and if the "hack" for gtk-- mentioned above does not work, then I see two solutions: <itemizedlist> <listitem><para> Define <command>std::</command> as a macro if the compiler doesn't know about <command>std::</command>. <programlisting> #ifdef OLD_COMPILER #define std #endif </programlisting> (thanks to Juergen Heinzl who posted this solution on gnu.gcc.help) </para></listitem> <listitem><para> Define a macro <symbol>NS_STD</symbol>, which is defined to either "" or "std" based on an autoconf-test. Then you should be able to use <command>NS_STD::string</command>, which will evaluate to <command>::string</command> ("string in the global namespace") on systems that do not put string in std::. (This is untested) </para></listitem> </itemizedlist> </para> </section> <section id = "sec-osprojects" label = "1.4"> <title id="sec-osprojects.title">How some open-source-projects deal with this</title> <para> This information was gathered around May 2000. It may not be correct by the time you read this. </para> <table><title>Namespace std:: in Open-Source programs</title> <tgroup cols = "2"> <tbody> <row> <entry><ulink url = "http://www.clanlib.org">clanlib</ulink> </entry> <entry>usual</entry> </row> <row> <entry><ulink url = "http://pingus.seul.org">pingus</ulink> </entry> <entry>usual</entry> </row> <row> <entry><ulink url = "http://www.mozilla.org">mozilla</ulink> </entry> <entry>usual</entry> </row> <row> <entry><ulink url = "http://libsigc.sourceforge.net"> libsigc++</ulink></entry> <entry>conservative-impl</entry> </row> </tbody> </tgroup> </table> <table><title>Notations for categories</title> <tgroup cols = "2"> <tbody> <row> <entry>usual</entry> <entry>mostly fully qualified names and some using-declarations (but not in headers)</entry> </row> <row> <entry>none</entry> <entry>no namespace std at all</entry> </row> <row> <entry>conservative-impl</entry> <entry>wrap all namespace-handling in macros to support compilers without namespace-support (no libstdc++ used in headers)</entry> </row> </tbody> </tgroup> </table> <para> As you can see, this currently lacks an example of a project which uses libstdc++-symbols in headers in a back-portable way (except for Gtk--: see the <link linkend="sec-gtkmm-hack" endterm="sec-gtkmm-hack.title">section on the gtkmm-hack</link>). </para> </section> </section> <!-- end of namespace-section --> <section id = "sec-nocreate" label = "2"> <title id="sec-nocreate.title">there is no ios::nocreate/ios::noreplace in ISO 14882</title> <para> I have seen <command>ios::nocreate</command> being used for input-streams, most probably because the author thought it would be more correct to specify nocreate "explicitly". So you can simply leave it out for input-streams. </para> <para> For output streams, "nocreate" is probably the default, unless you specify <command>std::ios::trunc</command> ? To be safe, you can open the file for reading, check if it has been opened, and then decide whether you want to create/replace or not. To my knowledge, even older implementations support <command>app</command>, <command>ate</command> and <command>trunc</command> (except for <command>app</command> ?). </para> </section> <section id = "sec-stream::attach" label = "3"> <title id="sec-stream::attach.title"><command>stream::attach(int fd)</command> is not in the standard any more</title> <para> Phil Edwards <email>pedwards@disaster.jaj.com</email> writes: It was considered and rejected. Not all environments use file descriptors. Of those that do, not all of them use integers to represent them. </para> <para> When using libstdc++-v3, you can use <funcsynopsis> <funcsynopsisinfo format="linespecific"> #include <fstream> </funcsynopsisinfo> <funcprototype> <funcdef> <function>basic_filebuf<...>::basic_filebuf<...> </function> </funcdef> <paramdef>__c_file_type* <parameter>file</parameter></paramdef> <paramdef>ios_base::open_mode <parameter>mode</parameter></paramdef> <paramdef>int <parameter>size</parameter></paramdef> </funcprototype> </funcsynopsis> but the the signature of this constructor has changed often, and it might change again. For the current state of this, check <ulink url="../ext/howto.html">the howto for extensions</ulink>. </para> <para> For a portable solution (among systems which use filedescriptors), you need to implement a subclass of <command>std::streambuf</command> (or <command>std::basic_streambuf<..></command>) which opens a file given a descriptor, and then pass an instance of this to the stream-constructor. For an example of this, refer to <ulink url="http://www.josuttis.com/cppcode/fdstream.html">fdstream example</ulink> by Nicolai Josuttis. </para> </section> <section id = "sec-headers" label = "4"> <title id="sec-headers.title">The new headers</title> <para> All new headers can be seen in this <ulink url="headers_cc.txt"> source-code</ulink>. </para> <para> The old C++-headers (iostream.h etc.) are available, but gcc generates a warning that you are using deprecated headers. </para> <section id = "sec-cheaders" label = "4.1"> <title id="sec-cheaders.title">New headers replacing C-headers</title> <para> You should not use the C-headers (except for system-level headers) from C++ programs. Instead, you should use a set of headers that are named by prepending 'c' and, as usual, omitting the extension (.h). For example, instead of using <filename class="headerfile"><math.h></filename>, you should use <filename class = "headerfile"><cmath></filename>. In some cases this has the advantage that the C++-header is more standardized than the C-header (i.e. <filename class="headerfile"><ctime></filename> (almost) corresponds to either <filename class = "headerfile"><time.h></filename> or <filename class = "headerfile"><sys/time.h></filename>). The standard specifies that if you include the C-style header (<filename class = "headerfile"><math.h></filename> in this case), the symbols will be available both in the global namespace and in namespace <command>std::</command> (but libstdc++ does not yet have fully compliant headers) On the other hand, if you include only the new header (i.e. <filename class = "headerfile"><cmath></filename>), the symbols will only be defined in namespace <command>std::</command> (and macros will be converted to inline-functions). </para> <para> For more information on this, and for information on how the GNU C++ implementation might reuse ("shadow") the C library-functions, have a look at <ulink url="http://www.cantrip.org/cheaders.html"> www.cantrip.org</ulink>. </para> </section> <section id = "sec-fstream-header" label = "4.2"> <title id="sec-fstream-header.title"> <filename class="headerfile"><fstream></filename> does not define <command>std::cout</command>, <command>std::cin</command> etc.</title> <para> In earlier versions of the standard, <filename class="headerfile"><fstream.h></filename>, <filename class="headerfile"><ostream.h></filename> and <filename class="headerfile"><istream.h></filename> used to define <command>cout</command>, <command>cin</command> and so on. Because of the templatized iostreams in libstdc++-v3, you need to include <filename class = "headerfile"><iostream></filename> explicitly to define these. </para> </section> </section> <section id = "sec-iterators" label = "5"> <title id="sec-iterators.title">Iterators</title> <para> The following are not proper uses of iterators, but may be working fixes for existing uses of iterators. <itemizedlist> <listitem><para>you cannot do <command>ostream::operator<<(iterator)</command> to print the address of the iterator => use <command>operator<< &*iterator</command> instead ? </para> </listitem> <listitem><para>you cannot clear an iterator's reference (<command>iterator = 0</command>) => use <command>iterator = iterator_type();</command> ? </para> </listitem> <listitem><para><command>if (iterator)</command> won't work any more => use <command>if (iterator != iterator_type())</command> ?</para> </listitem> </itemizedlist> </para> </section> <section id = "sec-macros" label = "6"> <title id="sec-macros.title"> Libc-macros (i.e. <command>isspace</command> from <filename class = "headerfile"><cctype></filename>)</title> <para> Glibc 2.0.x and 2.1.x define the <filename class="headerfile"><ctype.h></filename> -functionality as macros (isspace, isalpha etc.). Libstdc++-v3 "shadows" these macros as described in the <link linkend="sec-cheaders" endterm="sec-cheaders.title">section about c-headers</link>. </para> <para> Older implementations of libstdc++ (g++-2 for egcs 1.x and g++-3 for gcc 2.95.x), however, keep these functions as macros, and so it is not back-portable to use fully qualified names. For example: <programlisting> #include <cctype> int main() { std::isspace('X'); } </programlisting> will result in something like this (unless using g++-v3): <programlisting> std:: (__ctype_b[(int) ( ( 'X' ) )] & (unsigned short int) _ISspace ) ; </programlisting> </para> <para> One solution I can think of is to test for -v3 using autoconf-macros, and define macros for each of the C-functions (maybe that is possible with one "wrapper" macro as well ?). </para> <para> Another solution which would fix g++ is to tell the user to modify a header-file so that g++-2 (egcs 1.x) and g++-3 (gcc 2.95.x) define a macro which tells <filename class="headerfile"><ctype.h></filename> to define functions instead of macros: <programlisting> // This keeps isalnum, et al from being propagated as macros. #if __linux__ #define __NO_CTYPE 1 #endif [ now include <ctype.h> ] </programlisting> </para> <para> Another problem arises if you put a <command>using namespace std;</command> declaration at the top, and include <filename class = "headerfile"><ctype.h></filename>. This will result in ambiguities between the definitions in the global namespace (<filename class = "headerfile"><ctype.h></filename>) and the definitions in namespace <command>std::</command> (<command><cctype></command>). </para> <para> The solution to this problem was posted to the libstdc++-v3 mailing-list: Benjamin Kosnik <email>bkoz@redhat.com</email> writes: <quote> --enable-cshadow-headers is currently broken. As a result, shadow headers are not being searched.... </quote> This is now outdated, but gcc 3.0 still does not have fully compliant "shadow headers". </para> </section> <section id="sec-stream-state" label="7"> <title id="sec-stream-state.title">State of streams</title> <para> At least some older implementations don't have <command>std::ios_base</command>, so you should use <command>std::ios::badbit</command>, <command>std::ios::failbit</command> and <command>std::ios::eofbit</command> and <command>std::ios::goodbit</command>. </para> </section> <section id="sec-vector-at" label="8"> <title>vector::at is missing (i.e. gcc 2.95.x)</title> <para> One solution is to add an autoconf-test for this: <programlisting> AC_MSG_CHECKING(for container::at) AC_TRY_COMPILE( [ #include <vector> #include <deque> #include <string> using namespace std; ], [ deque<int> test_deque(3); test_deque.at(2); vector<int> test_vector(2); test_vector.at(1); string test_string("test_string"); test_string.at(3); ], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_CONTAINER_AT)], [AC_MSG_RESULT(no)]) </programlisting> If you are using other (non-GNU) compilers it might be a good idea to check for <command>string::at</command> separately. </para> </section> <section id="sec-eof" label="9"> <title>Using std::char_traits<char>::eof()</title> <para> <programlisting> #ifdef HAVE_CHAR_TRAITS #define CPP_EOF std::char_traits<char>::eof() #else #define CPP_EOF EOF #endif </programlisting> </para> </section> <section id="sec-string-clear" label="10"> <title>Using string::clear()/string::erase()</title> <para> There are two functions for deleting the contents of a string: <command>clear</command> and <command>erase</command> (the latter returns the string). <programlisting> void clear() { _M_mutate(0, this->size(), 0); } </programlisting> <programlisting> basic_string& erase(size_type __pos = 0, size_type __n = npos) { return this->replace(_M_check(__pos), _M_fold(__pos, __n), _M_data(), _M_data()); } </programlisting> The implementation of <command>erase</command> seems to be more complicated (from libstdc++-v3), but <command>clear</command> is not implemented in gcc 2.95.x's libstdc++, so you should use <command>erase</command> (which is probably faster than <command>operator=(charT*)</command>). </para> </section> <section id="sec-scan-form" label="11"> <title>GNU Extensions ostream::form and istream::scan</title> <para> These are not supported any more - use <link linkend="sec-stringstream" endterm="sec-stringstream.title"> stringstreams</link> instead. </para> </section> <section id="sec-stringstream" label="12"> <title>Using stringstreams</title> <para> Libstdc++-v3 provides the new <command>i/ostringstream</command>-classes, (<filename class="headerfile"><sstream></filename>), but for compatibility with older implementations you still have to use <command>i/ostrstream</command> (<filename class="headerfile"><strstream></filename>): <programlisting> #ifdef HAVE_SSTREAM #include <sstream> #else #include <strstream> #endif </programlisting> <itemizedlist> <listitem><para> <command>strstream</command> is considered to be deprecated </para> </listitem> <listitem><para> <command>strstream</command> is limited to <command>char</command> </para> </listitem> <listitem><para> with <command>ostringstream</command> you don't have to take care of terminating the string or freeing its memory </para> </listitem> <listitem><para> <command>istringstream</command> can be re-filled (clear(); str(input);) </para> </listitem> </itemizedlist> </para> <para> You can then use output-stringstreams like this: <programlisting> #ifdef HAVE_SSTREAM std::ostringstream oss; #else std::ostrstream oss; #endif oss << "Name=" << m_name << ", number=" << m_number << std::endl; ... #ifndef HAVE_SSTREAM oss << std::ends; // terminate the char*-string #endif // str() returns char* for ostrstream and a string for ostringstream // this also causes ostrstream to think that the buffer's memory // is yours m_label.set_text(oss.str()); #ifndef HAVE_SSTREAM // let the ostrstream take care of freeing the memory oss.freeze(false); #endif </programlisting> </para> <para> Input-stringstreams can be used similarly: <programlisting> std::string input; ... #ifdef HAVE_SSTREAM std::istringstream iss(input); #else std::istrstream iss(input.c_str()); #endif int i; iss >> i; </programlisting> One (the only?) restriction is that an istrstream cannot be re-filled: <programlisting> std::istringstream iss(numerator); iss >> m_num; // this is not possible with istrstream iss.clear(); iss.str(denominator); iss >> m_den; </programlisting> If you don't care about speed, you can put these conversions in a template-function: <programlisting> template <class X> void fromString(const string& input, X& any) { #ifdef HAVE_SSTREAM std::istringstream iss(input); #else std::istrstream iss(input.c_str()); #endif X temp; iss >> temp; if (iss.fail()) throw runtime_error(..) any = temp; } </programlisting> Another example of using stringstreams is in <ulink url="../21_strings/howto.html">this howto</ulink>. </para> <para> I have read the Josuttis book on Standard C++, so some information comes from there. Additionally, there is information in "info iostream", which covers the old implementation that gcc 2.95.x uses. </para> </section> <section id = "sec-about" label="13"> <title id="sec-about.title">About...</title> <para> Please send any experience, additions, corrections or questions to <ulink url = "mailto:fnatter@gmx.net">fnatter@gmx.net</ulink> or for discussion to the libstdc++-v3-mailing-list. </para> </section> </article> <!-- this is now obsolete, since the nwalsh-stylesheet generates an index <para> <itemizedlist> <listitem><para> <link linkend = "sec-nsstd" endterm = "sec-nsstd.title"/> </para></listitem> <listitem><para> <link linkend = "sec-nocreate" endterm = "sec-nocreate.title"/> </para></listitem> <listitem><para> <link linkend = "sec-stream::attach" endterm = "sec-stream::attach.title"/> </para></listitem> <listitem><para> <link linkend = "sec-headers" endterm = "sec-headers.title"/> </para></listitem> <listitem><para> <link linkend = "sec-iterators" endterm = "sec-iterators.title"/> </para></listitem> <listitem><para> <link linkend = "sec-macros" endterm = "sec-macros.title"/> </para></listitem> <listitem><para> <link linkend = "sec-about" endterm = "sec-about.title"/> </para></listitem> </itemizedlist> </para> --> <!-- Local Variables: compile-command: "xsltproc -o porting-howto.html docbook-xslt/docbook/html/docbook.xsl porting-howto.xml" End: -->