Topic: Language support of precompiled headers


Author: dacut@henry.ece.cmu.edu (David A. Cuthbert)
Date: 1997/04/21
Raw View
Paul D. DeRocco <strip_these_words_pderocco@ix.netcom.com> wrote:
>Fergus Henderson wrote:
>> Nope, Ilia's suggestion did not outlaw any existing code.
>> Ilia's suggestion was to add a new `$include' directive that
>> had different semantics to the existing `#include' directive.

>I didn't mean to suggest it outlawed existing code. I was saying that it
>didn't look that useful to me, since it eliminates some of the very
>capabilities that people actually use headers for. People don't use
>headers merely to take some declarations and put them into a separate
>file. They use them to allow the same declarations to be used in large
>numbers of unrelated programs.

The reason why this has happened is that C (and, therefore, C++) uses
pure textual file inclusion and macro substitution (at least for
project-specific headers; things like <iostream>, etc., can exist as
precompiled headers, etc.).  Depending upon your perspective, this
either opened back doors or provided additional functionality in the
type system.

I don't see a way around this in C.  C++, however, provides a number
of additional features (static const class members and templates)
which should eliminate the need for such pre-processor hacks.

>And in the real world, different programs
>need to steer the interpretation of headers to some extent, by defining
>different preprocessor symbols. An $include directive that specifically
>disallowed that would, in my view, be a directive of fairly limited
>usefulness. However, I'm willing to be proved wrong, if you have a good
>counterexample.

Consider the assert macro, one implementation of which might be:

#if !defined(NDEBUG)
#define assert(t)  if(t) abort()
#else
#define assert(t)  (void)(0)
#endif

A good C++ compiler should compile the following just as efficiently
(though I can imagine many current compilers, which have not-so-
debugged implementation of templates, generating inefficient code):

template<bool assertEnable>
inline void assert(bool test) {
 if(assertEnable && test)
  abort();
}

Using this is straightforward:

#include <assert>
static const bool  useAsserts = false;

int  myFunction(std::vector<int> listOfInts) {
 assert<useAsserts>(listOfInts.size() > 3);
 // ...
}

On the whole, I'm not a big fan of the C preprocessor and would like
to see all # directives eventually eliminated.  If I were to design a
language and base it loosely on C++, I think that #pragma might be the
only one to survive (and highly discouraged).
--
David A. Cuthbert (henry.ece.cmu.edu!dacut)
Graduate Student, Electrical and Computer Engineering
Data Storage Systems Center, Carnegie Mellon University
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/04/22
Raw View

"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:

>... in the real world, different programs
>need to steer the interpretation of headers to some extent, by defining
>different preprocessor symbols.

I think "need" is too strong here.  People often do it in C, because
it's convenient.  But there are other languages that don't provide
that sort of functionality, and people using those other languages
seem to get by without much trouble.

>An $include directive that specifically
>disallowed that would, in my view, be a directive of fairly limited
>usefulness. However, I'm willing to be proved wrong, if you have a good
>counterexample.

I don't know whether you would consider Ada to be a good counterexample ;-)

But to take a fairly common C/C++ example, with most implementations
it's easy to use `-I' options rather than `-D' options to steer the
interpretation of headers.  For example, if you have
standard-conforming headers, and headers with extra symbols, the
headers with the extra symbols can be defined by

 /* std/stdio.h */
 int printf(const char *, ...);

 /* extension/foo.h */
 #include <std/foo.h>
 void clearscreen();  /* clear the console */
 int gotoxy(int x, int y); /* position cursor at (x,y) */

I'm willing to be convinced of the usefulness of using #defines
and #if to steer the interpretation of headers, if you have good
enough examples.  But I think for most purposes you don't need that
functionality.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/22
Raw View

Tony Cook wrote:
>
> The reliance of the 16-bit headers on memory model isn't much of a
> problem, since I would assume that in such a scheme the 'environment'
> macros defined by the compiler (__LARGE__ for -ml in BC++ for example)
> would still be defined, just as __LINE__ and __FILE__ would still be
> defined.

Borland goes a step further in their RTL headers (albeit not in
windows.h), allowing the caller to specify different calling
conventions, in cast the programmer wants to recompile the library a
different way.

Anyway, there is a tradeoff between the desire to do as much
"compilation" in advance, which is the whole point of precompiled
headers, and the fact that changes in the caller's environment limits
how far you can compile without analogous changes being reflected in the
compiled output.

--

Ciao,
Paul

(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/23
Raw View

David A. Cuthbert wrote:
>
> A good C++ compiler should compile the following just as efficiently
> (though I can imagine many current compilers, which have not-so-
> debugged implementation of templates, generating inefficient code):
>
> template<bool assertEnable>
> inline void assert(bool test) {
>         if(assertEnable && test)
>                 abort();
> }
>
> Using this is straightforward:
>
> #include <assert>
> static const bool  useAsserts = false;
>
> int  myFunction(std::vector<int> listOfInts) {
>         assert<useAsserts>(listOfInts.size() > 3);
>         // ...
> }

(Why the template? Why not just test the constant inside the inline
function?)

You're certainly right that there are still many things that are done
with the preprocessor that could be done without, especially now that we
have templates.

But even the above case, if you want it to compile into the most
efficient code (i.e., not bothering to compute "listOfInts.size() > 3"
if assertEnable is false), then there's a limit to how much
pre-compiling you can do. Ideally, you'd like to compile to object code,
but you can't because you want certain object code completely left out
under some circumstances. So how far can you compile? In this case, you
could compile as far as the symbol table and parse tree, or maybe a tad
further. In some other situations, you can't even compile that far, but
can only go as far as the token stream. And where token pasting is used
(ugh), you can't even do that!

--

Ciao,
Paul

(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/23
Raw View

Fergus Henderson wrote:
>
> "Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
>
> >An $include directive that specifically
> >disallowed that would, in my view, be a directive of fairly limited
> >usefulness. However, I'm willing to be proved wrong, if you have a good
> >counterexample.
>
> I don't know whether you would consider Ada to be a good counterexample ;-)

Well, I meant a counterexample concerning C++.

> I'm willing to be convinced of the usefulness of using #defines
> and #if to steer the interpretation of headers, if you have good
> enough examples.  But I think for most purposes you don't need that
> functionality.

One change that would make it less necessary to use #defines would be to
allow any declaration that wasn't also a definition to be repeated. I
see lots of crud like this in headers:

#ifndef _DIV_T
#define _DIV_T
typedef struct {
        int     quot;
        int     rem;
} div_t;
#endif

so that the structure can be defined in more than one header. Why not
just allow the typedef to be repeated, as long as it's identical?

Another common use is for handling multiple memory models:

#ifndef _PTRDIFF_T
#define _PTRDIFF_T
#if     defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
typedef long    ptrdiff_t;
#else
typedef int     ptrdiff_t;
#endif
#endif

If you want your precompiled header to be more than just a binary token
string or a binary parse tree, then you really need separate versions
for the two sizes of ptrdiff_t, since the two sizes can result in
dramatically different code.

This is all becoming less and less important, I think, simply because
computers are getting faster and faster. Current precompiled header
technology on a nice fast Pentium is plenty fast, in my view, so I don't
particularly bemoan the lack of the hypothetical $include directive that
sparked this thread.

--

Ciao,
Paul

(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/23
Raw View

dacut@henry.ece.cmu.edu (David A. Cuthbert) writes:

|>  >And in the real world, different programs
|>  >need to steer the interpretation of headers to some extent, by defining
|>  >different preprocessor symbols. An $include directive that specifically
|>  >disallowed that would, in my view, be a directive of fairly limited
|>  >usefulness. However, I'm willing to be proved wrong, if you have a good
|>  >counterexample.
|>
|>  Consider the assert macro, one implementation of which might be:
|>
|>  #if !defined(NDEBUG)
|>  #define assert(t)  if(t) abort()
|>  #else
|>  #define assert(t)  (void)(0)
|>  #endif

But this is not a legal implementation.  The expansion of the assert
macro must be an expression.

|>  A good C++ compiler should compile the following just as efficiently
|>  (though I can imagine many current compilers, which have not-so-
|>  debugged implementation of templates, generating inefficient code):
|>
|>  template<bool assertEnable>
|>  inline void assert(bool test) {
|>   if(assertEnable && test)
|>    abort();
|>  }
|>
|>  Using this is straightforward:
|>
|>  #include <assert>
|>  static const bool  useAsserts = false;
|>
|>  int  myFunction(std::vector<int> listOfInts) {
|>   assert<useAsserts>(listOfInts.size() > 3);
|>   // ...
|>  }

But it doesn't have assert's functionality, far from it.  One of the
important points about assert is that I can turn it off and on within a
file, by #undef NDEBUG/#define NDEBUG and reincluding <assert.h>.

This isn't to say that this is the only way of achieving this end, or
even the best way.  Using your technique, for example, I could have
several distinct assertion functions: assert< userError >, assert<
internalError >, etc. which were turned on and off separately.  Or with
a slight modification, levels of assertion:

 static const int   assertionLevel = errorsAndUp ;

 assert< assertionLevel >( warning , condition1 ) ;
 assert< assertionLevel >( critical , condition2 ) ;

|>  On the whole, I'm not a big fan of the C preprocessor and would like
|>  to see all # directives eventually eliminated.  If I were to design a
|>  language and base it loosely on C++, I think that #pragma might be the
|>  only one to survive (and highly discouraged).

In practice, the only use of preprocessor directives other than #include
that appears in my code is conditional compilation on the
absense/presence of different language features.  Hopefully, these will
disappear when we have a standard.

This doesn't mean that I don't have system dependancies, but that
generally, I handle them by encapsulating them in a separate class, in a
separate file, in a separate directory.  A -I with the system dependant
directory brings in the correct version of the headers.  (For most of
the larger aspects -- reading directories, etc. -- I will work behind a
class firewall.  The interface, defined in the include file, is not
system dependant, and the only time I have to pull in the system
dependant files is when compiling the implementation.)

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/23
Raw View

fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) writes:

|>  I'm willing to be convinced of the usefulness of using #defines
|>  and #if to steer the interpretation of headers, if you have good
|>  enough examples.  But I think for most purposes you don't need that
|>  functionality.

You don't need it, but it does make code maintenance easier.  A simple
example: I use the -I option to pull in the correct machine file, but
this file only defined things like GB_HASEXCEPTIONS, etc.  It is
included from a global file, which contains:

 #if GB_HASEXCEPTIONS
 #define GB_BEGIN_TRY                    try {
 #define GB_END_TRY                      }
 #define GB_CATCH( cond )                } catch( cond ) {
 #define GB_RETHROW                      throw
 #else
 #define GB_BEGIN_TRY                    if ( 1 ) {
 #define GB_END_TRY                      }
 #define GB_CATCH( cond )                } else if ( 0 ) {
 #define GB_RETHROW
 #endif

Obviously, I could move all of the definitions into the machine file,
and avoid the #if.  But there are around a hundred lines of them, in
all, and it is, IMHO, preferable to keep the machine file as simple as
possible (about 20 or thirty lines, almost all of the sort: "#define
GB_HASxxxx 0").  Duplicating the above in 20 or 30 machine files seems
too error prone to me.

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/04/23
Raw View

David A Cuthbert writes:

> template<bool assertEnable>
> inline void assert(bool test) {
>  if(assertEnable && test)
>   abort();
> }

you probably meant && !test, right?

> Using this is straightforward:

> #include <assert>
> static const bool  useAsserts = false;

> int  myFunction(std::vector<int> listOfInts) {
>  assert<useAsserts>(listOfInts.size() > 3);
>  // ...
> }

Well, not so straightforward...  Here are some simpler (IMHO)
mechanisms:


The header file might define an assert function that takes two
arguments:

inline void assert(bool test, bool enable) { /*...*/ }

then users might redeclare assert to have a default value for the
second argument:

inline void assert(bool, bool = true);


Or assert could use a standard variable name as the default argument:

inline void assert(bool test, bool enable = useAssert) { /*...*/ }

So that users would have to declare useAssert and then include
<assert>:

static const bool useAssert = true;
#include <assert>


These alternatives, though, have the same problem of yours: the
condition is always evaluated, unless it can be inlined and known not
to have any side effects.  This could be prevented if assert were a
function that returned bool:

inline bool assert(bool test) {
  if (!test)
    abort();
  return test;
}

Then it would be used like this:

  useAsserts && assert(something);


Unfortunately, none of these is as simple and as efficient as the
standard C assert macro...

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: willer@interlog.com (Steve Willer)
Date: 1997/04/25
Raw View

dacut@henry.ece.cmu.edu (David A. Cuthbert) wrote:

>template<bool assertEnable>
>inline void assert(bool test) {
> if(assertEnable && test)
>  abort();
>}

This is missing two pretty important features of assertions: The ability
to dump the file and line number on assertion failure, and the ability
to display the expression on assertion failure. It also behaves
differently from the current assert in another way: In your example, the
test expression is always evaluated. This cannot be optimized out, and
can generate different side-effects from the existing assert.


----
Steve Willer
http://www.interlog.com/~willer/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/18
Raw View
Ilia Zemskov wrote:
>
>                            Abstract
>
>  In this article author suggests one direction of the C++ evolution
> - a language support of precompiled headers. Author explains idea and
> new C++ language constructions to provide better use of precompiled
> headers with C++ projects and shows benefits of this language
> improvement.

[etc.]

It seems that in the effort to make headers independent of the context
in which they are included, you've outlawed one of the main things that
people actually do with headers, which is to use previously defined
symbols to steer the interpretation of the header. The windows.h header
is full of this stuff, especially the 16-bit version which has to deal
with different pointer modifiers depending upon the memory model, etc.

--

Ciao,
Paul D. DeRocco

(Please send e-mail to mail:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/04/19
Raw View
"Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> writes:

>Ilia Zemskov wrote:
>>
>>  In this article author suggests one direction of the C++ evolution
>> - a language support of precompiled headers. Author explains idea and
>> new C++ language constructions to provide better use of precompiled
>> headers with C++ projects and shows benefits of this language
>> improvement.
>
>It seems that in the effort to make headers independent of the context
>in which they are included, you've outlawed one of the main things that
>people actually do with headers, which is to use previously defined
>symbols to steer the interpretation of the header.

Nope, Ilia's suggestion did not outlaw any existing code.
Ilia's suggestion was to add a new `$include' directive that
had different semantics to the existing `#include' directive.

Ilia's `$include "blah.h"' suggestion was in fact not that dissimilar to
Bjarne Stroustrups recent idea of an `include blah;' declaration.
I think that of all the criticisms in Ian Joyner's C++ critique, the
lack of a proper module system is C++'s worst weakness.  Bjarne suggested
a possible solution to this problem, but unfortunately the timing was not
good.  C++ is already complicated enough, and the time for major extensions
like this has passed.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: tony@online.tmx.com.au (Tony Cook)
Date: 1997/04/21
Raw View

Paul D. DeRocco (strip_these_words_pderocco@ix.netcom.com) wrote:

: It seems that in the effort to make headers independent of the context
: in which they are included, you've outlawed one of the main things that
: people actually do with headers, which is to use previously defined
: symbols to steer the interpretation of the header. The windows.h header
: is full of this stuff, especially the 16-bit version which has to deal
: with different pointer modifiers depending upon the memory model, etc.


I don't think I'd use the monolithic 16-bit windows.h as an example of
good programming practice.

The 32-bit headers are better organized in that they are split up on
sub-system boundaries (winuser.h, wingdi.h etc), but they also define
large numbers of macros.. which don't follow the normal C/C++
convention for using upper-case only.

The reliance of the 16-bit headers on memory model isn't much of a
problem, since I would assume that in such a scheme the 'environment'
macros defined by the compiler (__LARGE__ for -ml in BC++ for example)
would still be defined, just as __LINE__ and __FILE__ would still be
defined.
--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/21
Raw View

Fergus Henderson wrote:
>
> Nope, Ilia's suggestion did not outlaw any existing code.
> Ilia's suggestion was to add a new `$include' directive that
> had different semantics to the existing `#include' directive.

I didn't mean to suggest it outlawed existing code. I was saying that it
didn't look that useful to me, since it eliminates some of the very
capabilities that people actually use headers for. People don't use
headers merely to take some declarations and put them into a separate
file. They use them to allow the same declarations to be used in large
numbers of unrelated programs. And in the real world, different programs
need to steer the interpretation of headers to some extent, by defining
different preprocessor symbols. An $include directive that specifically
disallowed that would, in my view, be a directive of fairly limited
usefulness. However, I'm willing to be proved wrong, if you have a good
counterexample.

--

Ciao,
Paul D. DeRocco

(Please send e-mail to mail:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Ilia Zemskov" <zemskov@ashtech.msk.ru>
Date: 1997/04/17
Raw View
[Moderator's note: Despite the author's note at the beginning of this
message, it isn't actually crossposted.  This article was submitted
to, and is accordingly posted to, comp.std.c++ only.  mha]

    CROSSPOSTED TO:

      comp.lang.c++
      comp.lang.c++.moderated
      comp.std.c++
      relcom.fido.su.c-c++


                Fresh idea: C++ language support of precompiled headers
                -------------------------------------------------------


                           Abstract

        In this article author suggests one direction of the C++ evolution
     - a language support of precompiled headers. Author explains idea and
     new C++ language constructions to provide better use of precompiled
     headers with C++ projects and shows benefits of this language
     improvement.

                           *******

        Almost all C++ programmers know what is "precompiled headers". But
     let me give here a short description of this technique of software
     development (you may want to skip this description). So, some good C++
     compilers, for instance, latest versions of Borland C++ and Microsoft
     Visual C++, have feature called "precompiled headers", which helps to
     reduce compilation time of projects with many source files and large
     headers. In this article author will use abbreviation PH for "precompiled
     headers".
        With PH compiler compile header only once and then use results
     during compilation of sources, which include it. It's seems to me that
     it is work in following manner. When compile given header (.h) file
     first compiler creates (updates) a large binary file called "precompiled
     header" where it stores type and data definitions from header. After
     that, when compiler compile source (.c or .cpp) file, it use this
     definitions instead of recompiling header file again.
        But there are some inconvenient limitations: for example, header
     files to precompile "must" to be included in the same order in all
     source files; all source files should have equal defines which affect
     headers, etc. Compilers never check this limitations and this is
     inconvenient too.  Really it is true limitations only for headers
     depended on each other.
        This explanation of PH is not very clear, so, I recommend to readers
     who are unfamiliar with precompiled headers technique to become
     acquainted with it - not only to understand this article but to improve
     your own design facilities. For example, such readers can look at the
     documentation for compilers which support PH.

          Well, now my proposal. The programming language should provide
     support of precompiled headers. Why there is no such useful feature
     in C++ ? It has all that designer of objects may want, but not programmer.
        Author thinks that the root of evil is in imperfect preprocessor. So,
     to make it perfect we need at least to include preprocessor in the C++
     language. There will no any harm of this because C/C++ preprocessor
     is the de-facto standard.
        To provide the support of precompiled headers author suggests new
     preprocessor directive called "$include directive". Author thinks that
     it may be syntax construction such as:

     $include {
      <file1.h>
      <file2>
      "userfile.h"
     ...
     }

        Author will explain the semantics of this directive. Let us define
     term "definition" as one of the type definition, symbol defined by
     #define directive or data definition. We will use this meaning of
     "definition" only to explain the semantics of suggested directive.
     $include directive may appears in both .cpp and .h- files. All
     definitions from header included by the $include directive are visible in
     point of $include. Its semantics looks like the semantics of #include
     directive, but:

       (1) inside header included by $include directive the only visible
     definitions are definitions defined (declared) in this header or in
     headers included to this header by either $include or #include
     directive. So, such header is not affected by any other header unless
     other header is included in it;

       (2) all headers inside $include directive don't use values of any
     external #define directives but only values, defined from command line
     of compiler.

        Perhaps it is better to illustrate condition (1) by code
     example bellow.


     // ----------    File hdr.h    ---------------

     typedef int * pint;

     // ----------    End of file hdr.h    -------------




     // ----------    File src.cpp  ---------------

     #define int {}

     $include
     {
     "hdr.h"
     }

     pint  Variable;          // "pint" is int *
     main() int               // "int" is redefined to {}

     // ----------    End of file src.cpp    -------------


        In this example keyword "int" is not redefined in the file "hdr.h"
     but it is redefined in file "src.cpp" below #define directive.

        With such preprocessor facility C++ program will not be linear as now
     it is. It will like tree; source file will play role of root and headers
     will play role of other nodes.

        Now author want to define the term "standard header precompilation".
     Let us a future C++ compiler will have mode (or command- line switch)
     of standard header precompilation and (optionally) mode of non-
     standard header precompilation. In the last mode it may precompile
     headers in any way. In mode of standard header precompilation it will
     use the following rules:

     (important rules)
       1) compiler will never precompile headers with #include
     directive(s) inside their;
       2) compiler will precompile all headers included by $include directives
     as well as headers included to this headers by $include directive
     (recursively), if rule 1) is not applicable;

     (less important rules)
       3) inside either .cpp or .h-file an appearance of both $include and
     #include directives of the same header is an error;
       4) if .cpp file have both $include and #include directives for
     different headers then it's OK, but, of course, only headers, included
     by $include directives will be precompiled.

        When create precompiled header, compiler must store for every
     definition name of header, which is included in source file and where
     this definition is visible. Compiler must verify that source file include
     header before it make visible definitions from header in source file.
     As usual compiler must generate error messages for mismatch duplicate
     definitions.
        As described above, $include directive is a way to force headers to
     be not dependent from each other. So, with this language extension and
     appropriate compiler programmer may use $include directive to include
     headers to his sources in every order and precompile them. He is
     allowed to suppress unnecessary headers to include. He should not also
     worry about different defines before different includes of headers,
     only he should take care that all defines from command line are equal
     for all sources.
        Why C++ should provide this support ? The list of reasons, probably
     incomplete, is bellow.

     1) With this new feature you will be able to precompile headers for
     the same source code with different compilers and/or on different
     platforms.
     2) If you have a large project you may want to precompile user-
     written headers. With $include directive it will be much convenient.
     3) With "nonstandard header precompilation" you may, of course ,
     precompile headers for system libraries (such as <windows.h>). But if
     you will precompile headers for several system libraries, you should
     precompile the equal set of headers for all your sources or you will
     have no warranty that you project will be compiled correctly. It is
     inconvenient, especially for sources and headers, which are shared
     between different projects.
     4) In general: you can precompile headers now, but sometimes it
     is hard. With language support it will much easier.
     5) Many C++ compilers, for example GCC, have not precompiled headers
     because of it is a non- standard feature. When it will be standard
     feature, they will have.

        Author hopes that C++ designers and the C++ community will be
     attracted by this idea and, may be, by the suggested way of its
     implementation.



            With best regards,


     Ilya Zemskov                  e-mail:  zemskov@ashtech.msk.ru
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]