tags:

views:

197

answers:

4

We have these set of "utility" constants defined in a series of file. The problem arises from the fact that TOO MANY files include these global constant files, that, if we add a constant to one of those files and try to build, it builds the whole entire library, which takes up more than an hour.

Could anyone suggest a better way for this approach? That would be greatly appreciated.

+2  A: 

Do you really need every global define to be included in every file? You should probably split the constants up into categories and then split them into different files.

Every .h that is included is simply copied at that point in the file that is including it. If you change something in a file (either directly or via changing something that is included) then it absolutely needs to be recompile.

Another solution would be to have a .h file that has an accessor to a map of string name/values. Then in the .cpp file of that map/accessor you can insert the new values. Every new value you put would only need 1 file to be recompiled.

Another solution is not to include the header file anywhere. Simply extern in the variables you need in each .cpp file.

Brian R. Bondy
A: 

(Edit: I didn't think of external constants. Indeed, my idea is kinda stupid.)

(Edit: My "stupid" macro idea actually saves build time for when constants are added. Thanks for pointing that out, Brian!)

Use parallel building :-)

Seriously, I think one solution would be to create another header called utility_ex.hpp or something where you add new constants that you occasionally merge into utility.hpp (or whatever your current utility constants header is called).

Another (less efficient) solution would be to have a macro like this:

#define constant(name) get_constant(#name)
    // # means turn name into a string literal

int get_constant(const char *name);

Now suppose you want MAX_CUSTOMERS to be defined as 100. You can say:

constant(MAX_CUSTOMERS)

in the code. In get_constant's code, you might have:

int get_constant(const char *name) {
    if (!strcmp(name, "MAX_CUSTOMERS"))
        return 100;

    //shouldn't happen
    return -1;
}
Joey Adams
+1 not sure who voted you down, but I don't agree with them.... Of course you would use extern, but the problem the poster had was that when he ADDs a new constant he has to recompile everything. Extern needs to be used for global variables being included, but I think he already does this. It won't help with compiling less.
Brian R. Bondy
probably downvoted for the horrible runtime penalty of the "less efficient solution".
Georg Fritzsche
+5  A: 

First, if you are defining them directly in the header, I'd suggest instead delcaring them extern const, and then defining them in a cpp file:

//in .hpp:
extern const std::string foo;

//in .cpp:
const std::string foo = "FOO";

That way, at least definitions can be changed without a rebuild.

Second, examine where they are being included. If the constant file is being included in a low level header, can the include be moved to the cpp instead? Removing it might lower the coupling so it doesn't have to rebuild as much.

Third, break up that file. I'd suggest mapping out a structure you'd eventually want, start adding new constants to the new structure instead of the old file. Eventually (when you are sure you've got the structure you want), refactor the old file into the new structure, and make the old file include the entire structure. Finally, go through and remove all includes of the old file, pointing them at the appropriate new sections. That'll break up the refactoring so you don't have to do it all at once.

And fourth, you might be able to trick your compiler into not rebuilding if the header file changes. You'd have to check your compiler's documentation, and it might be unsafe, so you'd occasionally want to add full builds as well.

Todd Gardner
I'm sure he's already using extern or else he wouldn't be able to compile in the first place. The 4th suggestion about not compiling that file I think will only lead to problems and bugs. If you change your code you will want that change to be included.
Brian R. Bondy
@Brian: He needn't be using extern if he's got everything in the .h file to begin with. Todd is suggesting putting the value definition into a separate .cpp, with the declaration in the .h.
mos
Agreed. The whole idea of these 'God' objects is a bad one, usually introduced because developers were too lazy to do it right. Even *before* the new-fangled encapsulation caught on, modularization dictated that you should reduce coupling as much as possible to increase amintainability.
paxdiablo
Thanks for the suggestions. We are using the extern keyword, but we should break the constants file to separate pieces for sure. Again, thanks a lot.
+1  A: 

Perhaps it's time to do some refactoring to improve the cohesion and reduce the coupling in your software design. Splitting the global constant files would allow modules to be more selective about which constants need to be included, which will eliminate some of the unnecessary coupling. In the extreme case, you could break it all the way down to one constant per file, and ensure that each module only includes the constants it needs to use.

But that could result in poor cohesion, in the sense that the constants might naturally fall into related groups, such that a module that requires one constant will generally also require many others from that group. So the trick is to find a better grouping of constants in the various global files, then ensure that each module only includes what it needs.

Jim Lewis