Clearing outdated header spaghetti code

Any recommended spaghetti header cleanup methods that cause extremely slow compilation times (Linux / Unix)?

Is there any equivalent for "#pragma once" with GCC?
(found conflicting posts about this)

Thanks.

+4
source share
11 answers

Assuming you are familiar with the "include guard" (#ifdef at the beginning of the header ..), an additional way to speed up the build time is to use external enabled guards. This was discussed in the C ++ Large-Scale Software Development section. The idea is that the classic includes security devices, unlike #pragma once, it does not save you from parsing the preprocessor required to ignore the header the second time (i.e. He still has to figure it out and look for the beginning and end of the inclusion defender. external include guard, you put #ifdef around the #include line itself.

So it looks like this:

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

and of course, in the H file that you have classic, include guard

 #ifndef MY_HEADER #define MY_HEADER // content of header #endif 

Thus, the file myheader.h is not even opened / analyzed by the preprocessor, and it can save a lot of time in large projects, especially when the header files are located in shared remote places, as is sometimes the case.

again, everything in this book. Hth

+8
source

If you want to do a full cleanup and you have time to do it, the best solution would be to remove all #includes in all files (except for the obvious ones, for example abc.h in abc.cpp), and then compile the project. Add the necessary declaration or title to correct the first error, and then repeat it until you finish cleanly.

This does not eliminate the underlying problems that may lead to inclusion problems, but it ensures that only those included are necessary.

+6
source

I read that GCC believes that #pragma once outdated, although even #pragma once can only speed up the process so much.

To try to unravel the #include spaghetti, you can look at doxygen . It should be able to generate graphs of included headers, which can give you the edge in simplifying things. I cannot recall the details, but the graphical functions may require you to install GraphViz and indicate doxygen the path by which it can find GraphViz dotty.exe.

Another approach that you might consider if your compilation time is your main concern is to set up precompiled headers .

+4
source
Richard was right (why was his decision recorded?).

In any case, all C / C ++ headers should use include internal security devices.

This suggests that:

1 - Your old code is no longer supported, and you should use precompiled headers (which are a hack, but hey ... your need to speed up your compilation, not refactoring unsupported code)

2 - Your old code is still alive. Then you either use pre-compiled headers, or / or guards / external guards for a temporary solution, but in the end you will need to remove all of your included ones, one .C or .CPP at a time and compile each. C or .CPP one at a time, correcting their inclusion with forward-declarations or including if necessary (or even breaking up a large one, include in smaller ones so that each .C or .CPP file receives only the headers that it needs). In any case, testing and removing obsolete inclusions is part of the technical maintenance of the project, therefore ...

My own experience with precompiled headers was not entirely good, because for half the time the compiler could not find the character that I defined, and therefore I tried a complete clean / rebuild to make sure that it was not a precompiled header, which was outdated. Therefore, I suggest using it for external libraries that you won’t even touch (for example, the STL, C API, Boost headers, whatever). However, my own experience was with Visual C ++ 6, so I think (hopefully?), They got that right now.

So the last thing: headlines should always be self-contained. This means that if the inclusion of headers depends on the order of inclusion, then you have a problem. For example, if you can write:

 #include "AAA.hpp" #include "BBB.hpp" 

But not:

 #include "BBB.hpp" #include "AAA.hpp" 

because BBB depends on AAA, then all you have is a dependency that you never recognized in the code. Not recognizing this with a definition will make your compilation a nightmare. The BBB should also include AAA (even if it can be slightly slower: after all, forward declarations will be pure useless anyway, so you should have a fast compilation timer).

+3
source

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

  • find all #include instructions
  • delete one statement at a time and recompile
  • If compilation failed, add the include statement back to

In the end, you hopefully end up with the minimum amount needed in your code. You can write a similar script that includes re-settings to find out if they are self-contained or require other headers to be included in front of them (first include the header, see if compilation is not compiled, report it). This should somehow clear your code.

Some notes:

  • Modern compilers (gcc among them) recognize header protection and are optimized in the same way as pragma once, only opening the file once.
  • pragma can be problematic once if the same file has different names in the file system (i.e. with soft links)

  • gcc supports #pragma once, but calls it "deprecated"
  • pragma once is not supported by all compilers, not part of the C standard

  • not only compilers can be problematic. Tools like Incredibuild also have C # pragma once issues
+3
source

Use one or more of these to speed up assembly time.

  • Using Precompiled Headers
  • Use a caching mechanism (e.g. scons)
  • Use a distributed build system (distcc, Incredibuild ($))
+2
source

In the headers: include headers only if you cannot use the forward declaration, but always #include any file you need (including evil dependencies!).

0
source

As mentioned in another answer, you should definitely use forward declarations when possible. As far as I know, GCC has nothing that is equivalent to #pragma once, so I adhere to the old fashion style of the guards included.

0
source

Thanks for the answers, but the question is about existing code that includes strict "include order", etc. The question is if there are any tools / scripts to figure out what is actually happening.

Header protectors do not support the solution, since they do not allow the compiler to read the entire file again and again and ...

0
source

PC-Lint will be a long way to clear spaghetti headers. It will also solve other problems for you too, like uninitialized variables that are not visible, etc.

0
source

As soon as one of the users of livejournal.com commented on the answer to your question, some compilers support the inclusion of security optimization , which the linked page defines as follows:

The included security optimization is when the compiler recognizes the internal include include idium described above and takes steps to not open the file several times. The compiler can look at the include file, cut out comments and a space, and work if the entire file is inside security devices. If so, it saves the file name and turns on the protection status on the card. The next time the compiler is prompted to include a file, it can check the condition for enabling protection and decide whether to skip the file or # include it without opening the file.

Then you already answered that the external security guards are not the answer to your question. To disassemble the header files that should be included in a specific order, I would suggest the following:

  • Each .c or .cpp file must first #include create the corresponding .h file, and the rest of its #include directives must be sorted alphabetically. Usually you get build errors when it breaks the vague dependencies between the header files.
  • If you have a header file that defines global typedefs for base types or global #define directives that are used for most of the code, each .h file must be #include , this file first, and the rest of its <t22 directives> should be sorted into alphabetical order.
  • When these changes cause compilation errors, you usually have to add an explicit dependency on one header file to another, in the form of #include .
  • If these changes do not cause compilation errors, they can lead to behavioral changes. I hope you have some kind of test suite that you can use to test the functionality of your application.

It also seems that part of the problem may be that incremental assemblies are much slower than they should be. This situation can be improved by using forward declarations or a distributed build system, as others have pointed out.

0
source

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


All Articles