rfg@NCD.COM (Ron Guilmette) (02/05/91)
In article <15917@reed.UUCP> minar@reed.bitnet (Nelson Minar,L08,x640,7776519) writes: > >In C, I barely managed to keep all my header files straight and organized. >C++ just compounds my problems. Yes. It's a tricky business. Awhile back I invented a simple set of procedures for handling both header files and for dealing reasonably with inline functions. Basically, I try to keep a pair of files (e.g. foobar.C and foobar.h) for each and every class. This convention seem to keep things nice and simple. After I started doing that, I found that an awful lot of the time when I was making some change in the foobar.C file, I'd have to make a related change also in the foobar.h file. I got tired of having to edit one file (e.g. the foobar.C file) and then edit another (e.g. the foobar.h file) and then switch back again, so I invented a system where I could effectively keep all of the stuff from *both* the foobar.C and foobar.H files physically together in one file, thus making editing of related items (e.g. interface and implementation) easier. Basically, my system is this. For each class, I now create one file (e.g. foobar.C). It will look kind of like this: class foobar { ... public: foobar (); ... }; extern int foobar_related_variable; //############################################################## int foobar_related_variable = 0; foobar::foobar () { ... } Both the interface and the implementation are now in one file (which makes editing easier). The first part (i.e. the part above the line of ####'s is the interface part. The lower part is the implementation part. Now the real trick is that my makefiles (which use some special features of GNU make) automatically create or update the foobar.h file from the above foobar.C file on an "as needed" basis. To do this, I have to make use of a special category of files that don't otherwise exist. I call them ".timestamp" files. For each .C file, there is a rule in the makefile that says that there is a corresponding .timestamp file which depends on the .C file. In this example, that would be like: foobar.timestamp: foobar.C (Actually, GNU make lets me use a generic rule like "%.timestamp: %.C".) Anyway, the procedure for making a .timestamp file from a .C file is simple and fast. Basically it just involves some clever uses of grep and awk to find the line of #####'s in the .C file and then hacking off the hunk of the .C file which is above that line. This "interface" part then becomes the .timestamp file. Each time a .timestamp file gets updated (which happens each time the corresponding .C file got modified) an additional check takes place as a side-effect of the creation of the new .timestamp file. The side-effect is that the contents of the new .timestamp file are compared against the current contents of the corresponding .h file (using diff). If there are differences, it indicates that the most recent set of changes I made to the .C file actually *did* affect the "interface" part. In such cases, the (now stale) .h file is replaced by a copy of the current contents of the .timestamp file. (In cases where there was no .h file already, the action is the same as if the .h and .timestamp files were found to be different, i.e. the contents of the .timestamp file are copied into a newly created .h file.) This updating of the .h file causes the "last modification time" of the .h file to get changed. That's good because now make will know that it should re-make anything that depends upon that .h file. Note however that if the last set of changes that I made to my .C file did not cause the upper "interface" part to change, then I will get a new .timestamp file, but its contents will still be the same as the old contents of the .h file, so diff will yield an exit code of zero and thus, the .h file will *not* be touched at all. That's good because as long as I don't modify the "interface" part, I want to avoid unnecessary recompilations of stuff that depends upon just the interface part. This scheme allows me to prevent neadless recompilations from occuring. The neat part is that I actually break down my files into *three* parts like so: class foobar { ... public: foobar (); int inline_member (); int non_inline_member (); ... }; //################################################################ inline int foobar::inline_member () { ... } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int foobar::non_inline_member () { ... } Note that all inlines function are placed in the middle part. Now, if I want to build a small (or easily debuggable) version of my program, I use -Dinline="" and I have my makfiles treat everything above the line of ###'s as the "interface" part. However, when I want to build a fast production version of my program, I simply delete all of the existing .h files and re-make everything using the line of %%%'s as the dividing line between the interface and implementation parts. In the latter case, everything above the line of %%%%'s goes into the (automatically generated) .h file, and thus, I get all of my inline functions being inlined all over the place. This whole scheme is really trivial to implement using the special "generic rules" features of GNU make. Doing this stuff with some plain vanilla make program would be quite cumbersome. >Are constructs like '#pragma once' just entirely common in C++ headers? I >find them ugly.. I invented #pragma once. It is a non-standard GNU extension to the GNU C preprocessor. It is actually quite useful. What don't you like about it? Just saying that it is "ugly" is not very descriptive. I suppose that I could say the same about you, but that doesn't necessarily mean that you are a bad person. :-) -- // Ron Guilmette - C++ Entomologist // Internet: rfg@ncd.com uucp: ...uunet!lupine!rfg // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
loic@axis-design.fr (Loic Dachary) (02/07/91)
An what about protoize ? Do you use it in the process you describe ? Will protoize ever compile with and up-to-date gcc ? Please to not consider this an agression. I'm just curious. Thanks, Loic -- Loic Dachary loic@axis-design.fr or floic@afp.uucp Voice +33 1 40 35 20 20
rfg@NCD.COM (Ron Guilmette) (02/11/91)
In article <LOIC.91Feb7074009@axis-design.fr> loic@axis-design.fr (Loic Dachary) writes: > > An what about protoize ? Do you use it in the process you >describe ? Will protoize ever compile with and up-to-date gcc ? I've already requested (in one of the GNU newsgroups) for people who are interested in pre-testing protoize/unprotoize version 1.39.0 to contact me via E-mail. I have about 5 people who are supposed to be pre-testing the new version now, but I've only gotten actual feedback from two of them so far. If anybody else is interested in helping me pre-test protoize/unprotoize version 1.39.0, please send me mail. Note that you must be ready, willing, and able to build the GNU C compiler (GCC) also since neither protoize nor unprotoize can work without GCC. Oh, yes! You must also have access to the Internet (so that you can do anonymous FTP's) in order to be a pre-tester. -- // Ron Guilmette - C++ Entomologist // Internet: rfg@ncd.com uucp: ...uunet!lupine!rfg // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
gwu@nujoizey.tcs.com (George Wu) (02/13/91)
In article <3699@lupine.NCD.COM>, rfg@NCD.COM (Ron Guilmette) writes: |> In article <15917@reed.UUCP> minar@reed.bitnet (Nelson Minar,L08,x640,7776519) writes: |> > |> >In C, I barely managed to keep all my header files straight and organized. |> >C++ just compounds my problems. |> |> Yes. It's a tricky business. |> |> Awhile back I invented a simple set of procedures for handling both |> header files and for dealing reasonably with inline functions. |> |> [ a description of a system of generating header files from .C files |> deleted here for the sake of brevity ] I like Ron's method of generating header files from the .C file. We too have tried to do something similar, but rather generated the .C file from the header file. Obviously, this created problems since it's easier to generate function prototypes from implementation code than to automatically retrofit implementation code to new function prototypes. We eventually gave up this idea. |> |> This whole scheme is really trivial to implement using the special "generic |> rules" features of GNU make. Doing this stuff with some plain vanilla make |> program would be quite cumbersome. For reasons into which I which I won't go, we didn't like GNU make. I think I'll give this method a try with imake. Can anyone imagine any problems I might encounter with imake? George PS: For those unfamiliar with imake, it's an X utility program. Imake generates a makefile from a generic description and is used to generate machine specific makefiles in the X source distribution. ---- George J Wu, Software Engineer | gwu@tcs.com or uunet!tcs!gwu Teknekron Communications Systems, Inc.| (415) 649-3752 2121 Allston Way, Berkeley, CA, 94704 | Quit reading news. Get back to work.
gwu@nujoizey.tcs.com (George Wu) (02/13/91)
In article <1991Feb5.180503.24515@mathcs.sjsu.edu>, horstman@mathcs.sjsu.edu (Cay Horstmann) writes: |> In fact, the AWK script is very fast (although maybe Ron's method of |> running diff on a header portion is faster) and I just rerun it with |> each recompile. |> |> It doesn't matter much what method you or your shop uses for building .h |> files, as long as it is not the manual "gosh, I guess it is time to look |> at that .h file again" method. Won't generating a new .h file with each re-compile of the .C file cause *all* other .C files dependent upon the interface to be recompiled? Ron preserves the original file, and hence the last modification date make uses to determine if a recompile is necessary. This would save a lot of time in complex applications. George ---- George J Wu, Software Engineer | gwu@tcs.com or uunet!tcs!gwu Teknekron Communications Systems, Inc.| (415) 649-3752 2121 Allston Way, Berkeley, CA, 94704 | Quit reading news. Get back to work.
rfg@NCD.COM (Ron Guilmette) (03/03/91)
In article <1746@tcs.tcs.com> gwu@nujoizey.tcs.com (George Wu) writes: +In article <1991Feb5.180503.24515@mathcs.sjsu.edu>, +horstman@mathcs.sjsu.edu (Cay Horstmann) writes: +|> In fact, the AWK script is very fast (although maybe Ron's method of +|> running diff on a header portion is faster) and I just rerun it with +|> each recompile. +|> +|> It doesn't matter much what method you or your shop uses for building .h +|> files, as long as it is not the manual "gosh, I guess it is time to look +|> at that .h file again" method. + + Won't generating a new .h file with each re-compile of the .C file +cause *all* other .C files dependent upon the interface to be recompiled? +Ron preserves the original file, and hence the last modification date make +uses to determine if a recompile is necessary. This would save a lot of +time in complex applications. George has hit upon the real essence of my "tricky Makefile" scheme. Using this scheme allows you to avoid unnecessary recompilations in much the same way as an Ada "library manager" tool would allow you to avoid unnecessary recompilations of Ada compilation units. (Please excuse my use of the `A-word' in this newsgroup. I know that the mere mention of it makes certain people violently ill, and I'll try to avoid using it in future. :-) -- // Ron Guilmette - C++ Entomologist // Internet: rfg@ncd.com uucp: ...uunet!lupine!rfg // New motto: If it ain't broke, try using a bigger hammer.