Получение включенного пути к заголовочному файлу в VC++

Среда: я использую MS-VC++ 6.0,

  • Я включаю группу заголовочных файлов с некоторыми данными.
  • Файлы заголовков часто меняются, поэтому при каждом изменении я меняю настройку пути и перекомпилирую
  • Файл журнала создается на основе включенных файлов заголовков.
  • Для отслеживания файла заголовка из файла журнала я хочу распечатать путь к файлу заголовка внутри журнала.

  • Вопрос-1: возможно ли получить путь к заголовочному файлу из программы?

  • Вопрос-2: я использую VC++, но если это возможно в gcc, то я могу легко портировать, поэтому, пожалуйста, дайте мне знать, возможно ли это в любой другой среде, такой как gcc

person Alphaneo    schedule 08.12.2009    source источник
comment
Вы имеете в виду, что ваша программа генерирует журнал времени выполнения, который должен регистрировать все заголовочные файлы (по крайней мере, некоторые специально подготовленные), с которыми была скомпилирована программа?   -  person catchmeifyoutry    schedule 08.12.2009
comment
@Vainstah, я меняю путь к заголовочному файлу и перекомпилирую. Это очень простая вещь, которая, как мне казалось, была очевидной.   -  person Alphaneo    schedule 08.12.2009


Ответы (5)


В VC++ компиляция с параметром /FC поместит полный путь текущего обрабатываемого файла в макрос __FILE__.

Это будет учитывать ваши изменения в пути включения.

Подробности здесь.

person Drew Dormann    schedule 08.12.2009
comment
Я не понимаю, как это отвечает на любой вопрос? Является ли это альтернативой gcc? - person catchmeifyoutry; 08.12.2009

Конечно - внутри заголовочного файла поместите:

static const char *header_path = __FILE__;

.. затем просто напечатайте строку, на которую указывает header_path, в свой журнал.

person caf    schedule 08.12.2009
comment
И тогда каждая единица перевода, включающая этот заголовочный файл, получает свою собственную копию header_path :) - person pmg; 08.12.2009
comment
Я тоже об этом думал, но как получить единый список всех заголовочных файлов? Два файла заголовков с этой строкой не скомпилируются, и если вы используете разные имена переменных, вам все равно потребуется некоторая макрологика в вашем исходном коде для каждого добавляемого вами заголовка ... верно? - person catchmeifyoutry; 08.12.2009
comment
Я уверен, что видел компилятор, в котором __FILE__ не включал путь, а только часть имени файла. Не могу вспомнить, что, может быть, компилятор Intel x86, используемый каким-то эмулятором Symbian? Однако это нормально как для MSVC, так и для GCC, как и требовалось. - person Steve Jessop; 08.12.2009
comment
как получить единый список всех заголовочных файлов. Вы можете использовать цепочку инструментов для создания единого списка зависимостей файлов заголовков некоторых файлов cpp, а также сбрасывать результат в один файл cpp и компилировать его. Это должно быть довольно просто с использованием gcc и либо make, либо сценария оболочки, но я не могу предоставить эквивалент оболочки MSVC/Windows навскидку. - person Steve Jessop; 08.12.2009
comment
@pmg: вы можете избежать множественных определений, условно определив header_path с помощью некоторого макроса. Затем только #define этот макрос в logging.c или как там он называется. - person Steve Jessop; 08.12.2009
comment
@Steve: хорошо, я сам ответил на свой вопрос (добавил решение к ответам), набор инструментов не нужен. - person catchmeifyoutry; 08.12.2009

Вы имеете в виду, что имея #include "path/to/header.h", вы хотите вывести "path/to/header.h" из самой программы?

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

printf("Included: %s\n", INCLUDE_FILE);
person pmg    schedule 08.12.2009

Вы можете получить список включаемых файлов следующим образом.

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

экспортировать файлы make, которые создают файлы .mak и .dep. Включаемые файлы перечислены в файлах .dep.

Что касается идеи получения полного пути к включаемым файлам из работающей программы. Можно было бы использовать объектную модель msvc 6, чтобы вывести список путей включения файлов из IDE. Как только этот список станет известен. Можно использовать find file для поиска в этом списке путей интересующих включаемых файлов.

person EvilTeach    schedule 08.12.2009

Хорошо, вот решение (теперь, надеюсь, я вас правильно понял).

Он использует рекурсивные шаблоны, макрос __FILE__ и макрос __COUNTER__. Специальный заголовочный файл headerlisting.h содержит логику рекурсии шаблона и включает два полезных макроса (плюс несколько вспомогательных макросов).

  1. ADD_HEADER_FILE, просто добавьте эту строку в каждый заголовочный файл, который вы хотите включить в свой список.
  2. LIST_HEADER(headers), который вы можете поместить в свой исходный код, чтобы получить во время выполнения список всех включенных файлов заголовков.

Я уверен, что есть более простой способ сделать это, возможно, с помощью шаблона Boost p0werz, пожалуйста, прокомментируйте.

Ниже сначала headerlisting.h, а затем пример программы, содержащий два примера заголовков и исходный файл main(). Это работает в Linux с g++, надеюсь, что это работает и в Visual Studio (сейчас не могу проверить).

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__

Теперь пример программы:

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;
}

Сгенерированный вывод должен выглядеть следующим образом (если вы не исключите head1.h или head2.h из headertest.cpp):

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

Пожалуйста, скажите мне, что это работает.

person catchmeifyoutry    schedule 08.12.2009