[m-dev.] for review: automatic header file inclusion guards.

Fergus Henderson fjh at cs.mu.OZ.AU
Sun Jan 28 16:54:21 AEDT 2001


On 28-Jan-2001, Tyson Dowd <trd at cs.mu.OZ.AU> wrote:
> On 26-Jan-2001, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> > > Anyway, I don't want to waste time pushing this change past people who
> > > don't want it.  The other way to do this is to hash the contents of the
> > > foreign_decl string -- so I will write some code to do this instead.
> > 
> > That doesn't sound like a good idea either.  To avoid hash collisions,
> > you'd need a cryptographically secure hash function, and that might be
> > expensive to compute.  Furthermore, it's not the right semantics,
> > since if the user writes the same `foreign_decl' twice, it should get
> > included in their program twice, but what you propose would only
> > include it once.
> 
> You say "if the use writes the same `foreign_decl' twice, it should get
> included in their program twice".
> 
> But with the current implementation a single foreign_decl can be
> included any number of times (by #including and .opt file propogation).
> The number of times it is included in the program has no relationship
> with the number of foreign_decl pragmas.

Well, that's precisely what we're talking about changing.

> If you meant "included in the same scope twice",

I meant that each foreign_decl should be included in the program 
exactly once, and that the appropriate mechanism should be used
to import that declaration into scopes that use it.
For C, import means `#include', so C foreign_decls will get
#included into more than one translation unit.

> then for C code this is
> not useful at all.  In C, the same declarations given twice
> can only mean redeclaring exactly the same things, or giving a duplicate
> declaration error message (I think typedefs do this).  Neither of these
> leads any further expressiveness.

That's not completely true, because of #ifdef and other preprocessor
tricks.

	#ifndef COUNT
	  #define COUNT 1
	#elif COUNT == 1
	  #undef COUNT
	  #define COUNT 2
	#elif COUNT == 2
	  #undef COUNT
	  #define COUNT 3
	/* ... */
	#endif

That's probably not terribly useful in practice.
But there are some other more realistic cases.
For example, consider

	:- pragma c_header_code("#define NDEBUG").
	:- pragma c_header_code("#include <assert.h>").
	:- pragma c_header_code("inline void foo(void) { assert(0); }").

	:- pragma c_header_code("#undef NDEBUG").
	:- pragma c_header_code("#include <assert.h>").
	:- pragma c_header_code("inline void bar(void) { assert(0); }").

Also it is possible for users to include non-standard C extensions
which have side effects.  For example, some C implementations
have extensions such as

	#pragma warnings on		// enable warnings
	#pragma warnings off		// disable warnings
	#pragma warnings push		// save the current warning setting
	#pragma warnings pop		// restore the previous warning setting

which can be used in header files.  These have side effects, and so
the number of times that they are included is important.

> This is all a bit dicey, because we haven't really defined the meaning
> of foreign_decl.

Indeed!  It's not clear whether the example above with assert()
should be supported.

However, unless there is a good reason not to support it,
I think we should.

> But I think it should be defined along the lines of 
> 	"The declarations will be visible to any foreign_code in
> 	this module".
> It should *not* be defined as
> 	"The declarations will be pasted into the text of the program
> 	once for each foreign_decl pragma".

Why not?

Or, phrasing it more precisely:

	The foreign declarations will be pasted into the text of the
	program once for each foreign_decl pragma, in the same order
	that they occured in the Mercury module, in an appropriate
	place for publically visible declarations (e.g. for C they go
	in a header file), and these declarations will be imported in
	the appropriate manner for each language (e.g. using #include
	for C) into each place that contains foreign code that was
	defined in the same module as the foreign_decl pragma.

> If you want to get this, then you should use foreign_code, which should
> have semantics such as:
> 	"Each foreign code fragment will be compiled and included in the
> 	program".
> (this implies that multiple foreign code fragments will be compiled and
> included multiple times).

But that doesn't work for declarations which need to be visible to
other foreign code fragments.

> The cryptographically secure hash function is md5.  
> I don't think it is expensive enough to be worried about (about 0.5
> seconds to do 13Mb of text), 0.15 seconds to do all the 765 .m files in
> the tests module).

OK.

> > I think a better approach, at least for the MLDS back-end, would be to
> > ensure that each foreign_decl gets written to exactly one header file,
> > namely the one corresponding to the module that defined it.  Other C
> > files which might need those declarations should #include that header
> > file, rather than containing a copy of the foreign_decl.  In other words
> > the MLDS back-end should discard foreign_decls read from `.opt' files,
> > and just make sure sure that it #includes all the necessary headers.
> 
> This is reasonable too.  But it means you cannot put foreign_code from
> another module into your .opt or .trans_opt file, because the
> foreign_code doesn't have a context attached to it, so you cannot tell
> where you are supposed to include the .h file from.  I don't think we
> do this sort of optimization at the moment, but it sounds like one we
> should do someday.

Well, foreign_code from other modules definitely shouldn't get included
in `.opt' files, since each `.opt' file should only contain stuff from
its own module.  For `.trans_opt' files it would make sense, but we
could easily record the source module with such declarations in
`.trans_opt' files.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list