Читал, что люди прикручивают M4 к C/C++, чтобы получить более гибкий препроцессинг и делать всякие интересные вещи. Но почему-то никто не рассказывает, как он это сделал.
Проблема первая - от штатного препроцессора Си отказаться нельзя, потому что все системные заголовочные файлы используют его. Переписывать с нуля stdlib.h и прочие занятие плохое, тем более что они разные на разных платформах и даже версиях компилятора.
Решение - вызывать cpp до или после m4.
Проблема вторая - мы ведь хотим по-прежнему видеть красивые сообщения об ошибках с правильным указанием строки, где она случилась?
Решение - у m4 есть опция командной строки -s, которая включает генерацию специальных меток, которые помогут в этом деле компилятору (точно такие же метки вставляет и штатный препроцессор).
Проблема третья - при вызове двух препроцессоров подряд метки строк вступят в конфликт. Нет, конечно, файл скомпилится, однако информация о номерах строк станет странной.
Как решить эту проблему? Я вижу два возможных решения:
1) Как-то заставить M4 эмулировать CPP. Возможно, написав несколько макросов (однако вроде как нельзя объявлять макросы, начинающиеся с #, точнее можно, но вызывать их нужно по-особому).
2) Как-то сделать так, что номера строк будут сохранять актуальность.
UPD: Хорошая новость - CPP понимает метки строк, поставленные до него. То если запускать CPP после M4, метки строк будут верными. Я выяснил это эмпирически. Можно получить доказательство, что это так? Однако получается, что m4 не будет применяться к файлам, которые мы инклюдим с помощью #include. Окей. Допустим, во всём проекте будет использоваться m4_include для всех модулей. Однако как теперь определять зависимости сборки? Сейчас я использую gcc -MM.