4

A C or C++ compiler looks for header files using a strict set of rules: relative to the directory of the including file (if "" was used), then along the specified and default include paths, fail if still not found.

An ancillary tool such as a code analyzer (which I'm currently working on) has different requirements: it may for a number of reasons not have the benefit of the setup performed by a complex build process, and have to make the best of what it is given. In other words, it may find a header file not present in the include paths it knows, and have to take its best shot at finding the file itself.

I'm currently thinking of using the following algorithm:

  1. Start in the directory of the including file.

  2. Is the header file found in the current directory or any subdirectory thereof? If so, done.

  3. If we are at the root directory, the file doesn't seem to be present on this machine, so skip it. Otherwise move to the parent of the current directory and go to step 2.

Is this the best algorithm to use? In particular, does anyone know of any case where a different algorithm would work better?

8
  • 5
    Why don't you try and find out the list of include paths that the compiler would use? It should not be that difficult: there are some default ones, and the rest is passed in the command line using some compiler option (-I, /I, etc).
    – Giorgio
    Commented Nov 13, 2011 at 17:49
  • Yes, and if the project has a single command line, indeed this is not difficult. But many projects use thousands of lines of configuration files for build systems like autotools or cmake; worse yet, many projects use thousands of lines of custom build systems that an ancillary tool can't possibly know about; so for practical purposes, that information may not be available.
    – rwallace
    Commented Nov 13, 2011 at 17:59
  • Maybe you can run an indexer that indexes the available headers in the entire FS, make searching an already indexed file "step 0" followed by the steps you mentioned. I've seen the "locate" program on Linux that uses indexing(something like that) and is real fast. Commented Nov 13, 2011 at 18:43
  • That is certainly a possibility, but the issue is, supposing there are several header files in the filesystem with the same name, which one should be used? Not a hypothetical scenario: download the source code for a few large projects and see how many occurrences of e.g. config.h or index.h you end up with.
    – rwallace
    Commented Nov 13, 2011 at 18:58
  • 1
    I'd suggest this "algorithm": run the compiler with the flags necessary to trigger preprocessing and producing dependency rules. With the right flags you get a complete list of the exact include files that the compiler uses. Commented Oct 3, 2015 at 16:49

2 Answers 2

3

I'm currently thinking of using the following algorithm:

  1. Start in the directory of the including file.

  2. Is the header file found in the current directory or any subdirectory thereof? If so, done.

  3. If we are at the root directory, the file doesn't seem to be present on this machine, so skip it. Otherwise move to the parent of the current directory and go to step 2.

Is this the best algorithm to use? In particular, does anyone know of any case where a different algorithm would work better?

I have been working in projects that had a setup like this:

prj  
   |  
   +-config.h  
   |  
   +-sub_A  
   | |  
   | +-config.h  
   | +-...  
   |  
   +-sub_B
   | |  
   | +-config.h  
   | +-...  
   |  
   +-...

Those are then referred to as

#include "config.h"
#include "sub_A/config.h"
#include "sub_B/config.h"
...

Simply searching for a header with a matching file name would blow this, which I believe means that a different algorithm would work better.

7
  • Okay, how does your build system distinguish between the two? At first glance it would seem likely that sub_A/foo.c would want sub_A/config.h, but then how is prj/config.h referred to?
    – rwallace
    Commented Nov 13, 2011 at 19:39
  • @rwallace: See my edit.
    – sbi
    Commented Nov 13, 2011 at 19:45
  • Ah! Presumably with compiler switch -Iprj. Is there a reason to use "config.h" instead of <config.h>? Normally the quotes form tells the compiler to look first in the directory of the including file, which would seem not to apply here?
    – rwallace
    Commented Nov 13, 2011 at 19:49
  • @rwallace: I'm not sure I understand. The project is in prj, and that's also from where the build process is started. It's like the root of the build's file system. Files in the build folder are certainly included using the "" notation.
    – sbi
    Commented Nov 13, 2011 at 19:54
  • Sure, but there's a fine but important distinction: for most compilers, "" does not take the current directory as being the one from where the build process was started, but the one in which the file doing the including is located, as discussed here: stackoverflow.com/questions/7645024/… - are you saying you use a compiler that behaves otherwise? If so, which one?
    – rwallace
    Commented Nov 13, 2011 at 20:01
3

I think with any algorithm you won't succeed without knowing compiler command line used for particular file compilation. So, I see only two possibilities to use static analyzer with any build system:

  1. "lint way" (which is probably not very well aligned with you requirements) place utility right before or instead of compiler invocation, passing all the same arguments. In this case you should dig into any build system/makefile to find all rules responsible for compilation.
  2. "coverity way" run every build process under your tool, i.e. as a child/ren process(es). Thus, your tool should be clever enough to track which files are currently opening by compiler, which flags are passed. This is complicated but reliable way though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.