Почему двоичный вывод не равен при компиляции снова?

19

Я использую скрипт сборки для компиляции нескольких проектов C #. Бинарный вывод копируется в папку результатов, перезаписывает предыдущую версию файлов, а затем добавляется / передается в подрывную деятельность.

Я заметил, что двоичный вывод компиляции отличается, даже если вообще не было изменений в источнике или среде. Как это возможно? Разве бинарный результат не должен быть точно равным для одного входа?

Я не намеренно использую какие-либо специальные временные метки в любом месте, но компилятор (Microsoft, тот, который входит в .NET 4.0), возможно, сам добавляет метки времени?

Причина, по которой я спрашиваю, это то, что я делаю вывод в subversion, и из-за того, как работает наш сервер сборки, проверенные изменения вызывают перестройку, в результате чего еще раз измененные двоичные файлы проверяются в круге .     

задан mafu 19.01.2012 в 15:15
источник
  • subversion - как исходный, так и двоичный код звучит излишне для меня, разве вам лучше не хранить источники только под подрывной деятельностью? вы можете попытаться объединить сборки по мере необходимости с помощью решений, избегая необходимости выхода версии (я делаю что-то подобное, в среде sourceafe) –  Alex 19.01.2012 в 15:31
  • @alex Из-за огромного размера проекта и того, как работают наши команды, это нелегко в моем случае, но я обязательно попытаюсь идти в этом направлении. –  mafu 19.01.2012 в 15:51
  • Я создал запрос к MS, пожалуйста, повысьте: visualstudio.uservoice.com/forums/121579-visual-studio-2015/... –  Mr. TA 12.07.2016 в 16:48

4 ответа

28

ДРУГОЕ ОБНОВЛЕНИЕ:

С 2015 года команда компилятора прилагает усилия, чтобы получить источники недетерминизма из инструментальной цепочки компилятора, так что идентичные входы действительно дают идентичные результаты. Более подробную информацию см. В теге «Концепт-детерминизм» в github Roslyn.

UPDATE: Этот вопрос был предметом моего блога в мае 2012 года . Спасибо за отличный вопрос!

  

Как это возможно?

Очень легко.

  

Разве бинарный результат не должен быть точно равным для одного и того же входа?

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

Компилятор C # объединяет только что созданный GUID в сборке на каждой компиляции, тем самым гарантируя, что никакие две компиляции не дают точно такой же результат.

Более того - даже без GUID компилятор не дает никаких гарантий, что две «идентичные» компиляции будут давать одинаковые результаты.

В частности, порядок заполнения таблиц метаданных сильно зависит от деталей файловой системы; компилятор C # начинает генерировать метаданные в том порядке, в котором ему даны файлы, и которые могут быть тонко изменены различными факторами.

  

из-за того, как работает наш сервер сборки, проверенные изменения инициируют перестройку, в результате чего снова будут изменены бинарные файлы, которые будут проверяться в круге.

Я бы исправил это, если бы я был вами.

    
ответ дан Eric Lippert 19.01.2012 в 15:30
источник
  • Я помню, что gcc выпускал идентичные двоичные файлы (не уверен, что это гарантировано), поэтому поведение .NET меня удивило. Это имеет смысл, хотя. –  mafu 19.01.2012 в 15:37
  • @mafutrct: Люди действительно иногда удивляются этому. Например, правительственные агентства, которые просматривают код, который входит в игровые автоматы, ожидают, что они смогут получить исходный код и двоичный файл от поставщика, а также перекомпилировать исходный код и получить идентичный двоичный файл, доказательство ", что бинарные и источники совпадают. К сожалению, для них доказательство того, что бинарный файл соответствует его источникам, не является сервисом, который когда-либо утверждала команда C #, и поэтому им нужно найти другое решение. –  Eric Lippert 19.01.2012 в 15:42
  • @EricLippert: Это очень интересно. Я не смог найти информацию о вашем примере через веб-поиск. Есть ли в Интернете статья об этом? –  Brian 19.01.2012 в 16:42
  • Я иногда задавался вопросом, сохраняет ли компилятор свойство GUID каждого типа, который испускается в метаданные ... Я видел случаи, когда идентификатор GUID изменяется между рекомпиляциями, а также случаи, когда он остается неизменным. –  LBushkin 19.01.2012 в 23:15
  • Этот ответ устарел с наличием / детерминированного переключателя. –  Shiv 18.07.2017 в 05:25
Показать остальные комментарии
11

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

(Обратите внимание, что если source уже находится в Subversion, я бы вообще избегал добавления двоичных файлов. Обычно я включал только релизы сторонних библиотек. зависит от того, что вы делаете, хотя.)

    
ответ дан Jon Skeet 19.01.2012 в 15:16
источник
  • Есть ли простой способ избежать этого? –  mafu 19.01.2012 в 15:19
  • Двоичные файлы используются как входные данные для другого проекта, который находится в одном хранилище. (На самом деле, гораздо больше проектов.) –  mafu 19.01.2012 в 15:22
  • Вы можете сделать копию двоичных файлов где-нибудь, кроме выходного каталога, ссылку на копию и поместить копию двоичных файлов (но не самого выходного каталога) в элемент управления версиями. Конечно, если вы это сделаете, вам придется решить, чья ответственность заключается в том, чтобы обновить эту двоичную папку. Если эти два проекта очень тесно связаны, вы можете просто добавить сам проект в свой файл решения, а затем добавить ссылку на проект. Я думаю, что VS, вероятно, справится с этим сценарием разумно. –  Brian 19.01.2012 в 15:28
4

Как уже упоминалось другими, компилятор создает отдельную сборку, следовательно, другой результат. То, что вы ищете, это возможность создавать детерминированные сборки , и теперь это включено как часть компилятора roslyn.

Параметры командной строки Roslyn

  

/ детерминированный Произвести детерминированную сборку (включая модуль   GUID версии и временная метка)

Подробнее об этой функции Ссылка

    
ответ дан Alex Nolasco 23.06.2017 в 23:24
источник
  • Я вижу, что это доступно для MSBuild с VS2015. Можно ли это сделать и с devenv.com? Кажется, я не могу найти переключатель. Причина, по которой я спрашиваю, - MSBuild не поддерживает расширения, такие как Installer Projects, но в командной строке devenv. –  Shiv 18.07.2017 в 05:24
  • Найдены вы можете с помощью добавления группы свойств в .csproj <Project> <PropertyGroup> <Definistic> true </Definistic> </PropertyGroup> </Project> в соответствии с gist.github.com/aelij/b20271f4bd0ab1298e49068b388b54ae –  Shiv 18.07.2017 в 06:18
0

Насколько я знаю, на каждой компиляции разные бинарные файлы MS различны. Около 20 лет назад это было не так. После каждого компиляции двоичные файлы MS были одинаковыми (при условии, что исходный код был тем же).

    
ответ дан gregg 17.02.2016 в 04:13
источник