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

StackOverflow https://stackoverflow.com/questions/618581

Вопрос

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

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

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

static Reg regthisfile( __FILE__ );

Вы хотели бы сделать словарь I / 4 / "rel =" nofollow noreferrer "> Meyers singleton, чтобы избежать проблем с порядком создания.

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

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

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

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

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

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

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

Использование статических экземпляров в 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

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

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

  Singleton.register(__FILE__); 

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

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

static int doesntmatter = register( __FILE__);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top