Регистрация каждого исходного файла C / C ++ для создания списка используемых источников времени выполнения - PullRequest
1 голос
/ 06 марта 2009

Для библиотеки отладки и ведения журнала я хочу иметь возможность найти во время выполнения список всех исходных файлов, которые проект скомпилировал и связал. Я предполагаю, что буду включать какой-то заголовок в каждый исходный файл, и макрос препроцессора __FILE__ может дать мне символьную константу для этого файла, поэтому мне просто нужно каким-то образом «передать» эту информацию из каждого файла, чтобы она была собрана функция времени выполнения.

Вопрос в том, как сделать это элегантно, особенно если это можно сделать из C, а не из C ++. В C ++ я, вероятно, попытался бы создать класс со статическим хранилищем для хранения списка имен файлов. Каждый заголовочный файл создает локальный статический экземпляр этого класса, который при создании добавляет указатель FILE или что-либо еще в члены статических данных класса, возможно, в виде связанного списка.

Но я не думаю, что это будет работать в C, и даже в C ++ я не уверен, что гарантированно будет создан каждый элемент.

Ответы [ 9 ]

4 голосов
/ 06 марта 2009

Я бы не стал делать такие вещи прямо в коде. Я написал бы инструмент, который анализировал файл проекта (vcproj, makefile или даже просто сканировал каталог проекта на наличие файлов * .c *) и генерировал дополнительный исходный файл C, который содержал имена всех исходных файлов в некотором виде инициализированная структура данных.

Затем я бы включил этот инструмент в процесс сборки, чтобы каждый раз, когда вы выполняли сборку, все происходило автоматически. Во время выполнения все, что вам нужно сделать, это прочитать ту структуру данных, которая была построена.

2 голосов
/ 06 марта 2009

Существует стандартный способ для UNIX и Linux - ident. Для каждого исходного файла вы создаете тег ID - обычно он присваивается вашей системой контроля версий, например, ключевые слова SVN .

Затем, чтобы узнать имя и ревизию каждого исходного файла, вы просто используете команду ident. Если вам нужно сделать это во время выполнения, проверьте, как ident делает это - источник для него должен быть в свободном доступе.

2 голосов
/ 06 марта 2009

Я согласен с Ферруччо, лучший способ сделать это в системе сборки, а не в самом коде. Как расширение его идеи, добавьте в свою систему сборки цель, которая выводит список файлов (которые он должен знать в любом случае) в файл C в виде строки или массива строк, и скомпилируйте этот файл в исходный код. Это позволяет избежать больших сложностей в исходном коде и расширяется, если вы хотите добавить дополнительную информацию, такую ​​как номер версии из вашей системы контроля исходного кода, который создал исполняемый файл и т. Д.

1 голос
/ 06 марта 2009

Нет никакого способа сделать это на C. В C ++ вы можете создать такой класс:

struct Reg {
   Reg( const char * file ) {
      StaticDictionary::Register( file );
};

где StaticDictionary - это одноэлементный контейнер для всех ваших имен файлов. Тогда в каждом исходном файле:

static Reg regthisfile( __FILE__ );

Вы бы хотели сделать словарь Meyers синглтоном, чтобы избежать проблем с порядком создания.

0 голосов
/ 06 марта 2009

Я согласен с теми, кто говорит, что лучше избегать этого во время выполнения, но в C вы можете инициализировать статическую переменную с помощью вызова функции, то есть в каждом файле:

static int doesntmatter = register( __FILE__);
0 голосов
/ 06 марта 2009

Ужасная идея, я уверен, но использую синглтон. И на каждом файле сделать что-то вроде

  Singleton.register(__FILE__); 

в глобальном масштабе. Это будет работать только на файлах cpp. Я сделал что-то подобное несколько лет назад, как новичок, и это сработало. Но я хотел бы сделать это сейчас. Я бы добавил шаг сборки сейчас.

0 голосов
/ 06 марта 2009

Использование статических экземпляров в C ++ будет работать нормально.

Вы могли бы сделать это также в C, но вам нужно использовать специфические функции времени выполнения - для MSVC CRT посмотрите http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c6945/

Для C - вы можете сделать это с помощью макроса - определить переменную с именем, соответствующим вашему файлу, и затем вы можете сканировать символы вашего исполняемого файла, просто как идея:

 #define TRACK_FILE(name) char _file_tracker_##name;

используйте его в вашем my_c_file.c так:

 TRACK_FILE(my_c_file_c)

и затем grep всех имен файлов / переменных из двоичного файла, как это

nm my-binary | grep _file_tracker

Не очень хорошо, но ...

0 голосов
/ 06 марта 2009

В C ++ ваше решение будет работать. Это гарантировано.

Редактировать: Только что нашел решение в моей голове: Изменить правило в вашем make-файле, чтобы добавить '-включить' cfiles_register.h '' в каждый 'g ++ file.cpp'.

%.o : %.cpp
    $(CC) -include 'cfiles_register.h' -o $@ $<

поместите предложенную в вопросе реализацию в 'cfiles_register.h'.

0 голосов
/ 06 марта 2009

Я не думаю, что вы можете сделать это так, как вы наметили в «пассивном» режиме. То есть вы собираетесь каким-то образом запускать код для каждого исходного файла, который будет добавлен в реестр, трудно заставить его выполняться автоматически.

Конечно, возможно, что вы можете сделать этот код очень ненавязчивым, используя макросы. Это может быть проблематично для исходных файлов C, которые не имеют «точки входа», поэтому, если ваш код еще не организован как «модули», например, с. init() функция для каждого модуля, это может быть сложно. Статический код инициализации может быть возможен, я не уверен на 100%, если порядок, в котором происходит инициализация, создает проблемы здесь.

Использование static хранилища в модуле реестра звучит как отличная идея: простой связанный список или простая хеш-таблица должны быть достаточно простыми для реализации, если ваш проект еще не включает в себя универсальную служебную библиотеку. *

...