Может ли сборка из одного исходного кода выводить функционально разные исполняемые файлы?

Недавно мой коллега сказал что-то в этом роде: "Последовательные APK (исполняемые файлы), созданные сервером сборки из одного и того же исходного кода, могут быть не такими же". Контекст для этого обсуждения заключался в том, относится ли QA к построению X к построению Y, которое было выполнено одним и тем же сервером сборки (настроенным одинаково) из того же исходного кода.

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

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

Мои вопросы:

  • Правда ли, что последовательные сборки, выполненные одним и тем же сервером сборки из одного и того же исходного кода, могут быть функционально разными?
  • Если # 1 истинно, эти различия ограничены некорректно синхронизированным многопоточным кодом?
  • Если # 2 ложно, каковы другие части, которые могут измениться?

Ссылки на любые связанные с этим материалы будут оценены.

Ответ 1

Это, конечно, возможно в нескольких случаях. Предположим, вы используете Gradle для создания своего приложения для Android.

Случай 1:. Вы используете зависимую от третьей стороны, которая включена в шаблон подстановки версии, например:

compile somelib.1+

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

Случай 2:. Вы вводите информацию об окружающей среде в свое приложение, используя Gradle buildConfigFields. Эти значения будут введены в ваш класс приложения BuildConfig. В зависимости от того, как вы используете эти значения, поведение приложения может варьироваться в последовательных сборках.

Случай 3: Вы обновляете JDK на своих CI между последовательными сборками. Возможно, хотя я предполагаю маловероятным, что поведение вашего приложения может измениться в зависимости от того, как оно скомпилировано. Например, вы можете столкнуться с краем в JDK, который исправляется в более поздней версии, вызывая ранее выполненный ранее код, чтобы действовать по-другому.

Я думаю, что это отвечает на ваш первый вопрос и второй вопрос.

Изменить: извините, я думаю, что пропустил важную информацию от вашего OP. Мой случай 2 является примером вашего e.g. different timestamp, а случай 3 нарушает ваш configured the same way. Я оставлю здесь ответ.

Ответ 2

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

несколько советов: если возможно перестроить его, используйте подробный режим построения инструмента (например, -X в maven) и сравните вывод строки за строкой с некоторой программой diff

Ответ 3

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

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

Используя android/ gradle, одна из возможных причин привести к другому поведению или ошибкам в целом - это использовать + в вашем файле build.gradle для версий библиотеки. Вот почему вам следует избегать этого, поскольку последовательная сборка может извлекать более новую/другую версию, поэтому у вас будет другой исходный код, и, следовательно, он может создать функциональный исполняемый файл.

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

[...] последовательные сборки, выполненные одним и тем же сервером сборки из одного и того же исходного кода, могут быть функционально разными

Нет. Как описано выше, если вы используете одни и те же версии, тот же исходный код, он должен вызывать такое же поведение. Если вы не сделаете что-то очень плохое.

[...] Эти различия ограничены неправильно синхронизированным многопоточным кодом?

Это означало бы ошибку с вашим компилятором. Хотя это возможно, это крайне маловероятно.

[...] какие другие части могут измениться?

Помимо отметки времени и номера сборки ничего не изменится, учитывая тот же исходный код и конфигурацию.


Всегда полезно включать в свою сборку тесты (и другие). Таким образом, вы можете проверить, что конкретное поведение будет одинаковым с каждой сборкой.

Ответ 4

Они должны быть одинаковыми, кроме:

  • в системе сборки есть проблемы с потоком/оптимизацией.

  • аппаратные сбои Проблемы с CPU/RAM/HDD в среде сборки

  • время/код, связанный с платформой, в самой сборке или сценарии сборки

Итак, если вы строите точно такой же код на одном и том же HW, используя ту же самую версию системы сборки, ту же версию ОС и ваш код НЕ ОСОБЕННО ЗАВИСИМО ОТ результата времени сборки должен быть таким же. Они даже должны иметь точные контрольные суммы и размер.

Также результаты одинаковы ТОЛЬКО, если ваш код не зависит от внешних модулей, загружаемых из Интернета во время сборки, например, Gradle/Maven - вы не можете предоставить этим библиотекам то же самое, потому что они не находятся в управлении версиями. Кроме того, может быть зависимость, если версия модуля указана не точно (например, 2.0. +), Поэтому, если сопровождающий обновил этот модуль, ваша система сборки будет использовать обновленную версию → так что в основном ваши сборки, созданные из другого исходного кода.

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

Ответ 5

Пока этот вопрос касается Java/Android, Джон Скит писал о разных синтаксических анализаторах С#, обрабатывающих некоторые символы Unicode по-разному, в основном из-за изменений в Unicode символьная база данных.

В своих примерах Монгольский разделитель гласных (U + 180E) считается либо символом пробела, либо символом, допускаемым внутри идентификатора, что дает разные результаты в назначениях переменных.

Ответ 6

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

Представьте шаблон стратегии, который позволяет выбирать между алгоритмами во время выполнения и загружать один алгоритм на основе RNG.