Unraveling .h dependencies

What do you do when you have a set of .h files that fall prey to the classic "gordian knot" situation, where # include one .h means you end up with almost the entire batch? Prevention is certainly the best medicine, but what do you do when it happened before the provider (!) Sent the library?

Here's an addendum to the question, and this is probably a more lofty question - should we even try to unravel the dependencies in the first place ?;

+4
source share
4 answers

I did this based on C ++ code, which has already been split into many libraries (which was a good start).

I had to train (or guess) which library most depended on, which no longer depended on the code base. Then I processed each library in turn.

In turn, I looked at each module (* .cpp files) and made sure that its own header was included first and commented out the rest, then I commented out all #includes in this header file and then recompiled simply this module allows the compiler to tell me what do you need. I would not comment on the first heading, which seemed to be needed, and considered it, if necessary, recursive. It was interesting to see how many headings turned out to be unnecessary.

If only a name is required (because you have a pointer or link), use class name; or struct name; which is called a forward declaration and avoids the #include header file.

The compiler is very useful in telling you what dependencies are when you comment on #includes (you need to recompile with all the compilers you need to support portability).

Sometimes I had to move modules between libraries so that no pairs or groups of libraries depended on each other.

+4
source

Once you have the opportunity, you should reorganize the code to reduce it, which is too large, however, it assumes that you can achieve some kind of package cohesion. If you unravel things to find that every user of the code should include all the elements anyway, the end result is the same.

Another option is to use #defines to enable and disable partitions. Regardless of the fact that for the existing code base, the solution should move towards bundling packages.

Read: http://ivanov.files.wordpress.com/2007/02/sedpackages.pdf and research related to bundling packages.

+1
source

I unraveled this node several times, and it usually helps in maintaining the system to minimize .h dependencies as much as possible. There are decent tools for generating dependency trees (I used Klocwork at the time).

The drawback I found was with conditional compilation. Someone can delete the header file because they think we donโ€™t need it, but it turned out that we donโ€™t need it because VxWorks has some tricked headers ... on Solaris (or on any reasonable Posix system), which you need him.

+1
source

There is a balance between a huge number of finely organized headings and one heading that includes everything. Consider the Standard C library; there are a few great headers such as <stdio.h> , which declares many functions, but they are all related to I / O. There are other headers that are more of a variety - especially <stdlib.h> .

The Goddard Space Flight Center guidelines for C are noteworthy.

The basic rule is that each header should declare objects provided by a suitable (usually small) set of source files. Means and title should be self-contained. That is, if someone needs the code in the header of "something.h" , then this should be the only header that should be added to the compilation. If for "something.h" there are no objects that are not declared in the header, then they should include the appropriate headers. This may mean that the headers end, including <stddef.h> , because one of the functions uses, for example, size_t .

As @quamrana points out, you can use forward declarations for structures (not classes, since the question is labeled C, not C ++) when necessary, which primarily means when the interface accepts pointers and does not need to know the size of the structures or any member.

0
source

Source: https://habr.com/ru/post/1285870/


All Articles