Cleaning up Legacy Code “header spaghetti”

2019-06-24 01:47发布

Any recommended practices for cleaning up "header spaghetti" which is causing extremely slow compilation times (Linux/Unix)?

Is there any equvalent to "#pragma once" with GCC?
(found conflicting messages regarding this)

Thanks.

11条回答
我欲成王,谁敢阻挡
2楼-- · 2019-06-24 01:59

In headers: include headers only if you can't use forward declaration, but always #include any file that you need (include dependencies are evil!).

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-06-24 02:00

I've read that GCC considers #pragma once deprecated, although even #pragma once can only do so much to speed things up.

To try to untangle the #include spaghetti, you can look into doxygen. It should be able to generate graphs of included headers, which may give you an edge on simplifying things. I can't recall the details offhand, but the graph features may require you to install GraphViz and tell doxygen the path where it can find GraphViz's dotty.exe.

Another approach you might consider if compile time is your primary concern is setting up Precompiled Headers.

查看更多
\"骚年 ilove
4楼-- · 2019-06-24 02:05

PC-Lint will go a long way to cleaning up spaghetti headers. Also it will solve other problems for you too like uninitialised variables going unseen, etc.

查看更多
聊天终结者
5楼-- · 2019-06-24 02:06

I read the other day about a neat trick to reduce header dependencies: Write a script that will

  • find all #include statements
  • remove one statement at a time and recompiles
  • if compilation fails, add the include statement back in

At the end, you'll hopefully end up with the minimum of required includes in your code. You could write a similar script that re-arranges includes to find out if they are self-sufficient, or require other headers to be included before them (include the header first, see if compilation fails, report it). That should go some way to cleaning up your code.

Some more notes:

  • Modern compilers (gcc among them) recognize header guards, and optimize in the same way as pragma once would, only opening the file once.
  • pragma once can be problematic when the same file has different names in the filesystem (i.e. with soft-links)

  • gcc supports #pragma once, but calls it "obsolete"
  • pragma once isn't supported by all compilers, and not part of the C standard

  • not only compilers can be problematic. Tools like Incredibuild also have issues with #pragma once
查看更多
再贱就再见
6楼-- · 2019-06-24 02:07

Assuming you're familiar with "include guards" (#ifdef at the begining of the header..), an additional way of speeding up build time is by using external include guards. It was discussed in "Large Scale C++ Software Design". The idea is that classic include guards, unlike #pragma once, do not spare you the preprocessor parsing required to ignore the header from the 2nd time on (i.e. it still has to parse and look for the start and end of the include guard. With external include guards you place the #ifdef's around the #include line itself.

So it looks like this:

#ifndef MY_HEADER
#include "myheader.h"
#endif

and of course within the H file you have the classic include guard

#ifndef MY_HEADER
#define MY_HEADER

// content of header

#endif

This way the myheader.h file isn't even opened / parsed by the preprocessor, and it can save you a lot of time in large projects, especially when header files sit on shared remote locations, as they sometimes do.

again, it's all in that book. hth

查看更多
不美不萌又怎样
7楼-- · 2019-06-24 02:07

If you want to do a complete cleanup and have the time to do it then the best solution is to delete all the #includes in all the files (except for obvious ones e.g. abc.h in abc.cpp) and then compile the project. Add the necessary forward declaration or header to fix the first error and then repeat until you comple cleanly.

This doesn't fix underlying problems that can result in include issues, but it does ensure that the only includes are the required ones.

查看更多
登录 后发表回答