[comp.lang.c] include files -- help needed

guthriew@arcturus.uucp (Guthrie;Wade) (06/08/91)

I have this quandry regarding include files in a large (I mean *REALLY* 
large) software system.  The software team with which I am working is
developing a few hundred thousand line project which is broken up into 
several...let's call them "chunks".  The chunks communicate with each 
other by passing (message-specific) packets which are described by 'C'
structures.  The problem we face is managing the include files for the 
interface structures.  

We have around 15 chunks each of which must interface with several other 
chuncks (many of the chunks are things like utilities, BIT, database, 
stuff like that).  Beyond this, the software must interface with the 
operating system to deal with system resources, semiphores, inter-process
queues, etc.

In order to follow the guidelines of

	1) no nested include files and
	2) limiting the scope of globals and typedefs,

we have come up with an abysmally complex array of include files.  We
have essentially two include files for each pair of chunks (e.g., 
BIT-to-database and database-to-BIT interface definitions), an array of 
include files for constants, and another array for system resources.  A 
further problem arises when, for example, the "utilities" chunk has a 
common output format between itself and both BIT and database.

My question is this: How do other projects deal with this problem?  What
is used to partition the include files to try to keep the list of files 
small and at the same time limit the exposure of information (global data 
and type definitions) to chunks that do not use that information?  I am 
particularly interested in solutions used for big projects (e.g., BSD).

Thank you ever so much in advance.
-- 
Wade Guthrie (evil@arcturus.UUCP)    | "The likelihood of one individual being
...uunet!ccicpg!felix!arcturus!evil  | right increases with direct proportion to
Rockwell International; Anaheim, CA  | the intensity with which others are trying
My opinions, not my employer's.      | to prove him wrong", Mr. Jordan

bxw@ccadfa.adfa.oz.au (Brad Willcott) (06/08/91)

Your problem seems to me to be simple of solution.  That is unless I misread
your article.  Why don't you use preprocessor defines in your source files,
and test for them in your include files.  Here is an example:

---------- source.c ---------
#define BIT_to_DBMS
#include <header.h>

...
-----------------------------
---------- major.c ----------
#define SYSTEM_ACCESS
#include <header.h>

...
-----------------------------
--------- header.h ----------
#ifdef BIT_to_DBMS
...
#endif /* BIT_to_DBMS */

#ifdef SYSTEM_ACCESS
...
#endif /* SYSTEM_ACCESS */

#ifdef DBMS_to_BIT
...
#endif /* DBMS_to_BIT */
-----------------------------

If this is NOT a solution to your problem, then I DON'T understand it.

-- 
Brad Willcott,                          ACSnet:     bxw@ccadfa.cc.adfa.oz
Computing Services,                     Internet:   bxw@ccadfa.cc.adfa.oz.au
Australian Defence Force Academy,       UUCP:!uunet!munnari.oz.au!ccadfa.oz!bxw
Northcott Dr. Campbell ACT Australia 2600  +61 6 268 8584  +61 6 268 8150 (Fax)

stachour@sctc.com (Paul Stachour) (06/10/91)

guthriew@arcturus.uucp (Guthrie;Wade) writes:
> ...(stuff)   
>In order to follow the guidelines of

>	1) no nested include files and
>	2) limiting the scope of globals and typedefs,

> ...(more stuff)

    We have found the guideline of no nested include files
too restricting, as well as (my opinion) silly.  Anytime you
use a service-routine, you should not have to see how that
service routine works.  But if your access to a service routine 
depends (as it should) on the data-structures defined by that
sevice routine (such as a structure containing a complex number)
that you don't use, but that the set-of-service routines do,
  YOU SHOULD NOT BE REQUIRED TO INCLUDE THE DEFN OF COMPLEX NUMBERS

      And this principle applies though many levels of nesting.
We use the "protected" method to prevent the secondary problem in
C of including a file more than once. It's not a big thing, just
a slight increase in procrocessor time.

   Of course the way to work is to be in a language with real
modules, such as Ada, Euclid, or Modula2, but I suspect that
is not likely in your environment.

    Good Luck!  ..Paul (SCTC)
-- 
Paul Stachour          SCTC, 1210 W. County Rd E, Suite 100           
stachour@sctc.com          Arden Hills, MN  55112
                             [1]-(612) 482-7467

koerber.sin@sni.de (Mathias Koerber) (06/11/91)

In article <1991Jun7.233854.11170@arcturus.uucp> guthriew@arcturus.uucp (Guthrie;Wade) writes:
>
>In order to follow the guidelines of
>
>	1) no nested include files and
>	2) limiting the scope of globals and typedefs,

Why no nested include files? They are a *GOOD THING*, especially when one
include file automatically includes the definitions it references itself. On
pre-ansi compiler you must be a bit carefule about multiple inclusions though,
since not all headers have the

#ifndef THIS_IS_A_UNIQUE_DEFINE
#define THIS_IS_A_UNIQUE_DEFINE
...
#endif

code to skip the file when it was already included. Maybe you could add them
to your standard header files to make it even easier on the programmer. Just
be sure to pick unique_defines that are guaranteed to be really unique.

Mathias

chaplin@keinstr.uucp (chaplin) (06/21/91)

In article <1966@nixsin.UUCP> koerber.sin@sni.de writes:
>In article <1991Jun7.233854.11170@arcturus.uucp> guthriew@arcturus.uucp (Guthrie;Wade) writes:
>>
>>In order to follow the guidelines of
>>
>>	1) no nested include files and
>>	2) limiting the scope of globals and typedefs,
>
>Why no nested include files? They are a *GOOD THING*, especially when one
>include file automatically includes the definitions it references itself. On
>pre-ansi compiler you must be a bit carefule about multiple inclusions though,
>since not all headers have the
>
>#ifndef THIS_IS_A_UNIQUE_DEFINE
>#define THIS_IS_A_UNIQUE_DEFINE
>...
>#endif
>
>code to skip the file when it was already included. Maybe you could add them
>to your standard header files to make it even easier on the programmer. Just
>be sure to pick unique_defines that are guaranteed to be really unique.
>
>Mathias

One technique I have used to make the defines unique is to use the name of
the header file.  Eg, in my header file foobar.h you will find:

#ifndef FOOBAR_H
#define FOOBAR_H
...
#endif
-- 
Roger Chaplin / Instruments Division Engineering / "Though I'd been lost now I
chaplin@keinstr.uucp / CI$: 76307,3506          / felt I was found when He
#include <disclaimer.h>                        / looked at me with His
#include "disclaimer.h" /* cover all bases */ / forgiving eyes." - Michael Card

mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/26/91)

In article <1991Jun20.170144.1109@keinstr.uucp>, chaplin@keinstr.uucp (chaplin) writes:

> One technique I have used to make the defines unique is to use the
> name of the header file.  Eg, in my header file foobar.h you will
> find:

> #ifndef FOOBAR_H
> #define FOOBAR_H
> ...
> #endif

I used to do that too, until I found I had two time.h files, both using
TIME_H.  So now I tack on a 32-bit hash of the file contents (computed
by wraphfile, the program that throws the construct around the file in
the first place).  Now the time.hs use different defines.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

darcy@druid.uucp (D'Arcy J.M. Cain) (06/27/91)

In article <1991Jun26.091408.5023@thunder.mcrcim.mcgill.edu> der Mouse writes:
>> #ifndef FOOBAR_H
>> #define FOOBAR_H
>> ...
>> #endif
>I used to do that too, until I found I had two time.h files, both using
>TIME_H.  So now I tack on a 32-bit hash of the file contents (computed

Why go through that?  I assume you mean that you have something like time.h
and sys/time.h so just prepend _SYS_ to the defines in the sys directory:

  #ifndef _SYS_TIME_H
  #define _SYS_TIME_H
etc.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   There's no government
Toronto, Ontario, Canada           |   like no government!
+1 416 424 2871                    |

bhoughto@bishop.intel.com (Blair P. Houghton) (06/27/91)

In article <1991Jun26.213114.236@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:
>Why go through that?  I assume you mean that you have something like time.h
>and sys/time.h so just prepend _SYS_ to the defines in the sys directory:

Anyone know a system where one's not just a {link,symlink} to the other?

What is the difference?

				--Blair
				  "Fore!"

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (06/28/91)

In article <4896@inews.intel.com> bhoughto@bishop.intel.com (Blair P. Houghton) writes:
> In article <1991Jun26.213114.236@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:
> >Why go through that?  I assume you mean that you have something like time.h
> >and sys/time.h so just prepend _SYS_ to the defines in the sys directory:
> Anyone know a system where one's not just a {link,symlink} to the other?

Yep: a perfectly-standard-except-all-those-little-porting-bugs BSD 4.3
system.

> What is the difference?

They're not just different. They're incompatible. They end up defining
struct tm in two different ways; the people who ported the system to
this hardware managed to copy the definition from somewhere else to
<sys/time.h>.

As another example, our BSD 4.3+NFS Mt. XINU system has struct tm in
<time.h>. <sys/time.h> has various timefoo definitions for various foo,
then #ifndef KERNEL #include <time.h> #endif.

In any case, there are lots of other examples of include files where you
want to prepend the directory name instead of assuming a flat namespace.

---Dan

mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/29/91)

In article <1991Jun26.213114.236@druid.uucp>, darcy@druid.uucp (D'Arcy J.M. Cain) writes:
> In article <1991Jun26.091408.5023@thunder.mcrcim.mcgill.edu> der Mouse writes:
>>> #ifndef FOOBAR_H
>>> #define FOOBAR_H
>>> ...
>>> #endif
>> I used to do that too, until I found I had two time.h files, both
>> using TIME_H.  So now I tack on a 32-bit hash of the file contents
> Why go through that?  I assume you mean that you have something like
> time.h and sys/time.h so just prepend _SYS_ to the defines in the sys
> directory:

>   #ifndef _SYS_TIME_H
>   #define _SYS_TIME_H

Because there's no end to that.  Should I prepend
_USR_INCLUDE_SYS_TIME_H?  Or perhaps just _INCLUDE_SYS_TIME_H?  Why
should some of the leading directories be included but not the rest?

And I can't just strip off /usr/include, because the same scheme is
used for include files elsewhere.  Perhaps I should do _SYS_TIME_H and
then _THUNDER_HOME_SHAMASH_MOUSE_SUN4_INCLUDE_HTABLE_H for the htable.h
in my own include directory?

Ideally, the protection would protect against any inclusion of the same
file multiple times.  But there's no simple way to ensure that.

I suppose I could take the entire contents of the file, somehow process
it (reversibly) into a unique string that's a legal cpp symbol, and use
that.  But that triples the size of the file and will break some cpps
and stress the rest.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu