bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

new module 'c++defs'


From: Bruno Haible
Subject: new module 'c++defs'
Date: Mon, 22 Feb 2010 04:07:54 +0100
User-agent: KMail/1.9.9

Hi all,

Here come the proposed changes to allow C++ developers to choose among
the default mode with many
  #define func rpl_func
macro definitions and a "namespace mode", which is more in line with the
way C++ programs are built.

I handled all header files that do such #defines, except for
  - stat and stat64 - a difficult situation, which I prefer not to touch,
  - getopt.h - also tricky.

It essentially comes down to using different idioms than we used so far.
The new idioms are pretty straightforward; the changes are mostly
mechanical.

The new idioms require the prototype of each function being overridden
between 2 and 4 times. I kept this maintainable by using macros which
allow an easy copy&paste, and by keeping the 4 prototypes closely
together and lining up.

Two points that I'm not 100% satisfied with:
  - The suffix _SYS in _GL_FUNCDECL_SYS and _GL_CXXALIAS_SYS is a bit of
    a misnomer. This suffix designates the global namespace; the macros
    can apply also to substitutes for missing functions (where no rpl_
    is needed). But "global" cannot be abbreviated in 3 characters...
  - The set of functions that are stored in the gnulib namespace is
    arbitrary. Not all POSIX function are in there (e.g. strcmp is not,
    because gnulib does not have to deal with strcmp). On the other hand,
    not all functions in this namespace are POSIX or glibc functions:
    'mbslen' and 'mbschr' are not, but need replacements on some platforms.

Opinions? Suggestions?

Bruno


2010-02-21  Bruno Haible  <address@hidden>

        New module 'c++defs'.
        * modules/c++defs: New file.
        * build-aux/c++defs.h: New file.
        Reported by John W. Eaton <address@hidden>.

        Document C++ namespace mode.
        * doc/gnulib.texi (A C++ namespace for gnulib): New section.

============================= build-aux/c++defs.h =============================
/* C++ compatible function declaration macros.
   Copyright (C) 2010 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published
   by the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#ifndef _GL_CXXDEFS_H
#define _GL_CXXDEFS_H

/* The three most frequent use cases of these macros are:

   * For providing a substitute for a function that is missing on some
     platforms, but is declared and works fine on the platforms on which
     it exists:

       #if @GNULIB_FOO@
       # if address@hidden@
       _GL_FUNCDECL_SYS (foo, ...);
       # endif
       _GL_CXXALIAS_SYS (foo, ...);
       #elif defined GNULIB_POSIXCHECK
       ...
       #endif

   * For providing a replacement for a function that exists on all platforms,
     but is broken/insufficient and needs to be replaced on some platforms:

       #if @GNULIB_FOO@
       # if @REPLACE_FOO@
       #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
       #   undef foo
       #   define foo rpl_foo
       #  endif
       _GL_FUNCDECL_RPL (foo, ...);
       _GL_CXXALIAS_RPL (foo, ...);
       # else
       _GL_CXXALIAS_SYS (foo, ...);
       # endif
       #elif defined GNULIB_POSIXCHECK
       ...
       #endif

   * For providing a replacement for a function that exists on some platforms
     but is broken/insufficient and needs to be replaced on some of them and
     is additionally either missing or undeclared on some other platforms:

       #if @GNULIB_FOO@
       # if @REPLACE_FOO@
       #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
       #   undef foo
       #   define foo rpl_foo
       #  endif
       _GL_FUNCDECL_RPL (foo, ...);
       _GL_CXXALIAS_RPL (foo, ...);
       # else
       #  if address@hidden@   or   if address@hidden@ 
       _GL_FUNCDECL_SYS (foo, ...);
       #  endif
       _GL_CXXALIAS_SYS (foo, ...);
       # endif
       #elif defined GNULIB_POSIXCHECK
       ...
       #endif
*/

/* _GL_EXTERN_C declaration;
   performs the declaration with C linkage.  */
#if defined __cplusplus
# define _GL_EXTERN_C extern "C"
#else
# define _GL_EXTERN_C extern
#endif

/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);
   declares a replacement function, named rpl_func, with the given prototype,
   consisting of return type, parameters, and attributes.
   Example:
     _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
                                  _GL_ARG_NONNULL ((1)));
 */
#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \
  _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)
#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \
  _GL_EXTERN_C rettype rpl_func parameters_and_attributes

/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);
   declares the system function, named func, with the given prototype,
   consisting of return type, parameters, and attributes.
   Example:
     _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)
                                  _GL_ARG_NONNULL ((1)));
 */
#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \
  _GL_EXTERN_C rettype func parameters_and_attributes

/* _GL_CXXALIAS_RPL (func, rettype, parameters)
   declares a C++ alias called GNULIB_NAMESPACE::func
   that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
   Example:
     _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
 */
#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
  _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
#if defined __cplusplus && defined GNULIB_NAMESPACE
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
    namespace GNULIB_NAMESPACE                                \
    {                                                         \
      rettype (*const func) parameters = ::rpl_func;          \
    }                                                         \
    extern int _gl_cxxalias_dummy
#else
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
    extern int _gl_cxxalias_dummy
#endif

/* _GL_CXXALIAS_SYS (func, rettype, parameters)
   declares a C++ alias called GNULIB_NAMESPACE::func
   that redirects to the system provided function func, if GNULIB_NAMESPACE
   is defined.
   Example:
     _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
 */
#if defined __cplusplus && defined GNULIB_NAMESPACE
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
    namespace GNULIB_NAMESPACE                     \
    {                                              \
      rettype (*const func) parameters = ::func;   \
    }                                              \
    extern int _gl_cxxalias_dummy
#else
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
    extern int _gl_cxxalias_dummy
#endif

#endif /* _GL_CXXDEFS_H */
===============================================================================
diff --git a/doc/gnulib.texi b/doc/gnulib.texi
index 0a84691..d3c811b 100644
--- a/doc/gnulib.texi
+++ b/doc/gnulib.texi
@@ -614,6 +614,7 @@ before every release.
 @menu
 * Out of memory handling::
 * Obsolete modules::
+* A C++ namespace for gnulib::      A different way of using Gnulib in C++
 * Library version handling::
 * Windows sockets::
 * Libtool and Windows::
@@ -688,6 +689,72 @@ This module is obsolete.
 @end example
 
 
address@hidden A C++ namespace for gnulib
address@hidden A C++ namespace for gnulib
+
+The function definitions provided by Gnulib (@code{.c} code) are meant
+to be compiled by a C compiler.  The header files (@code{.h} files),
+on the other hand, can be used in either C or C++.
+
+By default, when used in a C++ compilation unit, the @code{.h} files
+declare the same symbols and overrides as in C mode, except that functions
+defined by Gnulib or by the system are declared as @samp{extern "C"}.
+
+It is also possible to indicate to Gnulib to provide many of its symbols
+in a dedicated C++ namespace.  If you define the macro
address@hidden to an identifier, many functions will be defined
+in the namespace specified by the identifier instead of the global
+namespace.  For example, after you have defined
address@hidden
+#define GNULIB_NAMESPACE gnulib
address@hidden smallexample
address@hidden
+at the beginning of a compilation unit, Gnulib's @code{<fcntl.h>} header
+file will make available the @code{open} function as @code{gnulib::open}.
+The symbol @code{open} will still refer to the system's @code{open} function,
+with its platform specific bugs and limitations.
+
+The symbols provided in the Gnulib namespace are those for which the
+corresponding header file contains a @code{_GL_CXXALIAS_RPL} or
address@hidden macro invocation.
+
+The benefits of this namespace mode are:
address@hidden
address@hidden
+Gnulib defines fewer symbols as preprocessor macros.  For example, on a
+platform where @code{open} has to be overridden, Gnulib normally does
address@hidden open rpl_open}.  If your package has a class with a member
address@hidden, for example a class @code{foo} with a method @code{foo::open},
+then if you define this member in a compilation unit that includes
address@hidden<fcntl.h>} and use it in a compilation unit that does not include
address@hidden<fcntl.h>}, or vice versa, you will get a link error.  Worse: You
+will not notice this problem on the platform where the system's @code{open}
+function works fine.  This problem goes away in namespace mode.
+
address@hidden
+It provides a safety check whether the set of modules your package requests
+from Gnulib is sufficient.  For example, if you use the function
address@hidden::open} in your code, and you forgot to request the module
address@hidden from Gnulib, you will get a compilation error (regardless of
+the platform).
address@hidden itemize
+
+The drawback of this namespace mode is that the system provided symbols in
+the global namespace are still present, even when they contain bugs that
+Gnulib fixes.  For example, if you call @code{open (...)} in your code,
+it will invoke the possibly buggy system function, even if you have
+requested the module @samp{open} from gnulib-tool.
+
+You can turn on the namespace mode in some compilation units and keep it
+turned off in others.  This can be useful if your package consists of
+an application layer that does not need to invoke POSIX functions and
+an operating system interface layer that contains all the OS function
+calls.  In such a situation, you will want to turn on the namespace mode
+for the application layer --- to avoid many preprocessor macro
+definitions --- and turn it off for the OS interface layer --- to avoid
+the drawback of the namespace mode, mentioned above.
+
+
 @node Library version handling
 @section Library version handling
 

Attachment: patches.tar.bz2
Description: application/tbz


reply via email to

[Prev in Thread] Current Thread [Next in Thread]