views:

436

answers:

5

Environment: I am using MS-VC++ 6.0,

  • I include a group of header file with some data.
  • The header files change often, so on every change I change the path setting and re-compiler
  • A log file is generated based on the included header files
  • For tracking of the header file from the log file, I wish to print the header file path inside the log

  • Question-1: Is getting the header file path from inside the program possible?

  • Question-2: I am using VC++, but if it is possible in gcc, then I can easily port, so, please let me know, if it is possible in any other environment like gcc
+1  A: 

Sure - inside the header file put:

static const char *header_path = __FILE__;

..then just print the string pointed to by header_path into your log.

caf
+1, Nice and simple idea.
Alphaneo
And then every translation unit that includes that header file, gets its own copy of header_path :)
pmg
I was thinking about that too, but how do you get a single list of all header files? Two header files with that line would not compile, and if you use different variable names you would still need some macro logic in your source for every header you add ... right?
catchmeifyoutry
I'm sure I've seen a compiler where `__FILE__` didn't include the path, just the filename part. Can't remember what, though, maybe the Intel x86 compiler used by some Symbian emulator? It's fine for both MSVC and GCC, though, as requested.
Steve Jessop
"how do you get a single list of all header files". You could use the toolchain to generate a single list of header file dependencies of some cpp file(s), and dump the result into a single cpp file and compile it. This should be pretty straightforward using gcc and either `make` or a shell script, but I can't provide a MSVC/Windows shell equivalent off the top of my head.
Steve Jessop
@pmg: you can avoid the multiple definitions by conditionally defining `header_path` with some macro. Then only `#define` that macro in logging.c, or whatever it's called.
Steve Jessop
@Steve: ok, I answered my question my self (added a solution to the answers), no toolchain needed.
catchmeifyoutry
+1  A: 

Do you mean that having #include "path/to/header.h", you want to print "path/to/header.h" from the program itself?

#define INCLUDE_FILE "path/to/header.h"
#include INCLUDE_FILE

printf("Included: %s\n", INCLUDE_FILE);
pmg
+4  A: 

In VC++, compiling with the option /FC will put the currently processed file's entire path in the __FILE__ macro.

That will account for your changes to the include path.

Details here.

Shmoopty
+1 /FC switch was news to me. Thanks.
Alphaneo
+1 Yes, very nice.
EvilTeach
I don't get it, how does this answer either question? Is the are gcc alternative?
catchmeifyoutry
A: 

You can get the list of include files like this.

(project)
(export makefile)
(write dependencies when writing make files)

export the make files, which creates .mak files and .dep files. The include files are listed in the .dep files.

As to the idea of getting the full path to the include files from within the running program. One might be able to use use the msvc 6 object model, to pull the list of include file paths out of the IDE. Once that list is known. One could use find file, to search that list of paths for the include files of interest.

EvilTeach
A: 

Ok, here is a solution (now I hope I understood you correctly).

It uses Recursive Templates, the __FILE__ macro, and the __COUNTER__ macro. A special headerlisting.h header file contains the logic for the template recursion, and includes two useful macros (plus some helper macro's)

  1. ADD_HEADER_FILE, just add this line to every header file you want to include in your list.
  2. LIST_HEADER(headers), which you can put in your source to retrieve at run-time a list of all the included header files

I'm sure there is an easier way to do this, maybe with Boost's templating p0werz, please comment.

Below is first headerlisting.h, and then an example program containing two example headers and a main() source file. This works on Linux with g++, hope it works in Visual Studio too (can't test right now).

headerlogic.h

#ifndef __HEADERLOGIC_H__
#define __HEADERLOGIC_H__

// By catchmeifyoutry, 2009-12-08
//  See http://stackoverflow.com/questions/1863995/getting-included-header-file-path-in-vc

#include <vector>
#include <string>

namespace HeaderListing
{

// Recursive templates to store header files, templatized by a header index I.
// Header files will be stored by template specialization, adding new specializations
// for every new header.
//
// The recursive headers depend on the assumption that the for the previous index I-1
// there is a HeaderFile<I-1> defined which contains a method
//   void HeaderFile<I-1>::list_headers(std::vector<std::string> &headers)
// to list all I-1 previous header files.
// The I-th HeaderFile then defines it's own list_header(...) to add one name
// to the list.

// -------------------------------------
// Recursive case
//    By default, list_headers() adds no name to the list, but if this default case
//    is specialized with c-string for name, it will add to the list
template <int I>
class HeaderFile
{
public:
    typedef HeaderFile<I-1> PrevHeader;

    // in the specalization, this will store the name of header file;
    // but if no header with index I is given, name will be NULL by default
    static const char * name;

    // in the recursive case
    static inline void list_headers(std::vector<std::string> &headers)
    {
        PrevHeader::list_headers(headers);
        if (name != NULL) {
            headers.push_back(name);
        }
    }
};
template <int I> const char * HeaderFile<I>::name = NULL;

// -------------------------------------
// Base case
//    Ensures recursion ends, implements dummy list_headers()
template <>
class HeaderFile<-1>
{
public:
    static inline void list_headers(std::vector<std::string> &headers)
    { /* end of recursion, do nothing! */ }
};

}; // namespace HeaderListing

// -------------------------------------
// Macros to add header files

// Add n-th header file name (as a string) to the list
#define ADD_HEADER_FILE_NAME_N(n, file) template <> const char * HeaderListing::HeaderFile<n>::name = __FILE__; \

// Add a given string (e.g. a header filename) to the to the list
//   Uses built-in __COUNTER__ macro to track the current header count.
//   NOTE: it doesn't matter if count was used in between since there can be gaps in between the header indices
#define ADD_HEADER_FILE_NAME(file) ADD_HEADER_FILE_NAME_N(__COUNTER__, file)

// Add the current (header) file to the list
//   Uses the built-in __FILE__ macro.
#define ADD_HEADER_FILE ADD_HEADER_FILE_NAME(__FILE__)

// List all defined header files
//   The "headers" argument should be a std::vector<std::string>
#define LIST_HEADERS(headers) HeaderListing::HeaderFile<__COUNTER__>::list_headers(headers);

#endif // __HEADERLOGIC_H__

Now for the example program:

head1.h

#ifndef __HEAD1__
#define __HEAD1__

#include "headerlisting.h"
ADD_HEADER_FILE

#endif // __HEAD1__

head2.h

#ifndef __HEAD2__
#define __HEAD2__

#include "headerlisting.h"
ADD_HEADER_FILE

#endif // __HEAD2__

headertest.cpp

#include <iostream>
#include <vector>
#include <string>

#include "headerlisting.h"
#include "head1.h" // <-- TRY COMMENTING THESE OUT!
#include "head2.h" // <-- TRY COMMENTING THESE OUT!

using namespace std;

int main()
{
    // list included header files
    vector<string> headers;
    LIST_HEADERS(headers);

    // display included header files
    size_t n = headers.size();
    cout << "Found " << n << " headers" << endl;
    for (size_t h = 0; h < n; ++h)
    {
        cout << "header " << h << " :\t" << headers[h] << endl;
    }

    return 0;
}

The generated output should look like this (if you don't exclude the head1.h or head2.h from headertest.cpp, that is):

Found 2 headers
header 0 :  head1.h
header 1 :  head2.h

Please tell me this works.

catchmeifyoutry