Конечной целью является сравнение 2 двоичных файлов, построенных из одного и того же источника в одной и той же среде, и возможность сказать, что они действительно функционально эквивалентны.
Одним из приложений для этого было бы сосредоточение времени QA на вещах, которые фактически были изменены между релизами, а также мониторинг изменений в целом.
MSVC в тандеме с форматом PE, естественно, делает это очень трудно.
До сих пор я нашел и нейтрализовал эти вещи:
- Временная метка PE и контрольная сумма
- Запись каталога цифровой подписи
- Отметка времени отладки
- подпись, возраст и путь к файлу PDB
- Временная метка ресурсов
- Все версии файлов/продуктов в ресурсе VS_VERSION_INFO
- Раздел цифровой подписи
Я анализирую PE, находит смещения и размеры для всех этих вещей и игнорирует байтовые диапазоны при сравнении двоичных файлов. Работает как шарм (ну, для нескольких тестов я его запустил). Я могу сказать, что подписанный исполняемый файл с версией 1.0.2.0, построенный на Win Server 2008, равен unsigned one, версии 10.6.6.6, построенный на моем блоке разработчика Win XP, если версия компилятора и все источники и заголовки одинаковы. Это похоже на VC 7.1 - 9.0. (Для релизов)
С одной оговоркой.
Абсолютные пути для обеих строчек должны быть одинаковыми должны иметь одинаковую длину.
cl.exe преобразует относительные пути в абсолютные и помещает их в объекты вместе с флагами компилятора и так далее. Это оказывает непропорциональное воздействие на целые двоичные файлы. Изменение одного символа в пути приведет к тому, что один байт изменится здесь и там несколько раз на весь .text-раздел (хотя многие объекты были связаны, я подозреваю). Изменение длины пути приводит к значительно большим различиям. И в obj файлах, и в связанных двоичных файлах.
Похоже, что путь к файлу с флагами компиляции используется как некоторый хэш, что делает его связанным двоичным или даже влияет на порядок размещения несвязанных фрагментов скомпилированного кода.
Итак, вот вопрос из трех частей (суммируется как "что теперь?" ):
-
Должен ли я отказаться от всего проекта и вернуться домой, потому что то, что я пытаюсь сделать, нарушает законы физики и корпоративную политику MS?
-
Предполагая, что я обрабатываю проблему абсолютного пути (на уровне политики или обнаружив магический флаг компилятора), есть ли какие-то другие вещи, на которые я должен обратить внимание? (такие вещи, как __TIME__, означают измененный код, поэтому я не против того, чтобы их не игнорировали).
-
Есть ли способ заставить компилятор использовать относительные пути или обмануть его, думая, что путь не такой, какой он есть?
Причина для последней - красиво раздражающая файловая система Windows. Вы просто никогда не знаете, что при удалении нескольких файлов из источников и объектов и метаданных svn не удастся из-за блокировки файлов изгоев. По крайней мере, создание нового корня всегда преуспевает, пока остается свободное место. Проблема с одновременным запуском нескольких сборок. Запуск пучка виртуальных машин, в то время как решение, довольно тяжелое.
Интересно, есть ли способ настроить виртуальную файловую систему для процесса и его дочерних элементов, чтобы несколько деревьев процесса увидели разные "C:\build" dirs, частные для них только в одно и то же время.. Небольшая виртуализация сортов...
UPDATE:, мы недавно открыли инструмент GitHub. См. Раздел Сравнить в документации.