Собираем VirtualBox под Windows

  • Tutorial

 Введение


Как известно большинству пользователей Windows-версии VirtualBox (далее — VB, не путать с Visual Basic), в релизе 4.3.14 разработчики этой программы добавили дополнительный механизм защиты, называемый «hardening» (что можно перевести как «упрочнение»), который привёл к многочисленным проблемам совместимости VB с антивирусами, драйверами крипто-модулей и даже отдельными обновлениями самой Windows, в результате чего виртуальные машины попросту отказываются запускаться. В лучшем случае пользователю приходится ждать около месяца, пока проблемная программа, о которой он сообщит разработчикам, окажется учтена в следующем релизе VB. В худшем случае придётся либо удалять конфликтующую программу (или системное обновление), либо откатывать VB до версии 4.3.12 — последней, в которой не было этой защиты. Многочисленные предложения к разработчикам о добавлении пользовательского списка исключений или опции, отключающей защиту целиком, остаются без внимания. Единственный внятный ответ с их стороны звучит так: «не хотите защиту — компилируйте из исходников сами». Что ж, придётся этим заняться.

Несмотря на то, что процедура сборки описана на официальной вики, она неполна и кое в чём устарела, а сама сборка так и норовит выдать странные ошибки. Поэтому когда я всё-таки пробился до конца сей процедуры, я решил, что её описание заслуживает отдельной статьи. Инструкция время от времени обновляется и на текущий момент адаптирована для VB версии 6.0.4, но если кого-то заинтересует сборка более ранних версий VB или библиотек, информацию можно выцарапать из истории правок.

 Содержание

» Постановка задачи
» Пара предупреждений
» Готовим окружение
» Особенности установки программ
» Последние штрихи
» Собираем VirtualBox
» Послесловие
» Дополнения

 Постановка задачи


Изначально я планировал упростить себе задачу и обойтись минимальной пересборкой, чтобы устанавливать официальный дистрибутив и просто подменять в нём бинарные файлы. Однако оказалось, что такой подход не сработает, поскольку не учитывает использование системных механизмов установки и регистрации драйверов и COM-компонентов. Можно было бы попытаться разобраться в деталях и написать автоматизирующий скрипт, но я решил замахнуться на более крупную дичь: самостоятельно собрать полноценный дистрибутив, максимально близкий к официальному и отличающийся от него только отсутствием hardening'а.

Сразу скажу, что на 100% задачу решить не удалось. Слабым звеном оказались гостевые дополнения, которые в официальном пакете собраны под Windows (32- и 64-битную), OS/2, Linux и некоторые другие *NIX-системы. В комментариях соответствующего Makefile указано, что сборка осуществляется удалённо на разных машинах, а настраивать такой комплект виртуалок мне не улыбалось. В итоге я решил собирать из исходных кодов всё, кроме дополнений, ISO-образ которых буду просто скачивать с сервера Oracle. Я пока не исследовал вопрос наличия hardening'а в дополнениях, но даже если он там есть, сообщений о вызванных им проблемах мне до сих пор не попадалось.

 Пара предупреждений


• Проблемы безопасности

Про hardening известно, что добавили его не просто так, а для закрытия некой уязвимости VB. Подробно рассказать о сути уязвимости Oracle категорически отказывается, несмотря на то, что в официальных дистрибутивах проблема исправлена много лет назад. В общих чертах речь идёт о том, что системный механизм внедрения библиотек в чужие процессы в случае VB может приводить к неавторизованному повышению привилегий на хостовой машине, и что для этой уязвимости VB есть реально использующиеся эксплойты. Если это вас не пугает, можете продолжать чтение, но я вас предупредил.

• Подписывание драйверов

Как известно, начиная с Vista, 64-битная Windows в обычном режиме запрещает загрузку драйверов, не подписанных сертификатом с цепочкой доверия, ведущей до корневого сертификата Microsoft (а в Windows 10 при загрузке с включённым Secure Boot драйверы и вовсе должны быть подписаны непосредственно самой Microsoft). Поэтому прежде чем компилировать VB даже для личного использования, необходимо продумать решение этой проблемы: либо купить сертификат, либо попробовать воспользоваться сервисами подписывания драйверов для разработчиков open source (если они, конечно, согласятся подписать заведомо уязвимый драйвер), либо перевести свою Windows в тестовый режим и использовать самоподписанный тестовый сертификат.

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

 Готовим окружение


Официально в качестве сборочной системы рекомендуется Windows версии от 7 до 10. Всю работу я проводил в Windows 7 SP1 x64, но, думаю, что с другими версиями проблем возникнуть не должно. Если вы выделяете для сборки отдельную машину (реальную или виртуальную), имейте в виду, что ей необходим доступ в Интернет.

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

Следующий набор программ поставляется только в виде инсталляторов (по крайней мере, официально). Для Visual Studio и SDK/WDK важно соблюдать порядок установки, как указано ниже. После установки крайне желательно установить обновления через Windows Update с включённой опцией поддержки всех продуктов Microsoft.
  • Visual Studio 2010 Professional
    Для полноценной сборки требуется именно 2010, причём не ниже Professional. В версии 2010 Express нет библиотеки ATL, необходимой для сборки COM API, через который работают фронт-энды. Я сделал несколько попыток перенести проект на VS 2013 или 2015 Community Edition, чтобы избавиться от необходимости платной лицензии (которую к тому же сейчас крайне проблематично купить), но, увы, безуспешно.
  • Windows SDK v7.1
  • Visual Studio 2010 SP1
  • Visual C++ 2010 SP1 Compiler Update for SDK 7.1
  • Windows Driver Development Kit (WDK) v7.1
  • Windows SDK v8.1
  • ActivePerl
  • ActivePython 2.7
  • Cygwin

Остальные программы скачиваются в виде архивов или исходных кодов:

Также потребуются два архива:

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

  • SDK 8.1
    Для сборки будет использоваться SDK версии 7.1, версия 8.1 требуется только для утилиты SignTool: в 7.1 отсутствует поддержка двойного подписывания SHA-1/SHA-256. Если у вас есть компьютер с установленным SDK версии 8.1 или более поздней, можно просто скопировать утилиту signtool.exe оттуда (со всеми зависимостями) и указать соответствующий путь в файле LocalConfig.kmk (см. ниже).
  • WiX
    Это инструмент для создания MSI-инсталляторов. Хоть финальный вариант инсталлятора и является EXE-файлом, внутри он содержит два MSI, так что WiX тут необходим. Если вам достаточно простой компиляции бинарников, то этот пакет не понадобится.
  • SDL
    На этой библиотеке основан фронт-энд VBoxSDL.exe — минималистичная альтернатива стандартной оболочке VirtualBox.exe. Если вам не требуется VBoxSDL, то, может быть, удастся обойтись без библиотеки SDL, но я это не проверял.
  • gSOAP
    Этот компонент необходим для сборки сервиса удалённого управления VB: VBoxWebSrv.exe. Отсутствие gSOAP не является критической ошибкой, VB успешно соберётся без этого сервиса.
  • libvpx, libopus
    Видео- и аудиокодек, использующиеся для записи видео с экрана виртуальной машины. При их отсутствии VirtualBox собирается и работает корректно, а функция записи просто игнорируется (хотя и показывает анимацию, будто запись выполняется).
  • Cygwin
    Требуется для сборки libvpx.
  • MiKTeX
    При помощи MiKTeX компилируется справочник в формате PDF (doc\UserManual.pdf). Отсутствие MiKTeX не является критической ошибкой, VB успешно соберётся без PDF-документации.
  • NASM
    Этот ассемблер будет использоваться для сборки OpenSSL. Поддерживается и сборка без внешнего ассемблера, но с ним будет создан более оптимальный код.

Чтобы легче было отслеживать потенциальные источники проблем сборки, привожу здесь сводную таблицу всех инструментов с их версиями и путями установки в созданном мной окружении. Обозначение «{x32|x64}» указывает, что пакет устанавливается в два разных каталога для 32- и 64-битной версии.
Программа Версия Путь установки
Visual Studio 2010 Professional C:\Program Files (x86)\Microsoft Visual Studio 10.0\
SDK 7.1 C:\Program Files\Microsoft SDKs\Windows\v7.1\
SDK 8.1 C:\Programs\DevKits\8.1\
WDK 7.1.0 C:\WinDDK\7600.16385.1\
ActivePerl 5.26.1 Build 2601 x64 C:\Programs\Perl\
ActivePython 2.7.14.2717 x64 C:\Programs\Python\
WiX 3.11.1.2318 C:\Programs\WiX\
Qt 5.6.3 C:\Programs\Qt\5.6.3-{x32|x64}\
MinGW-32 4.5.4 C:\Programs\mingw32\
MinGW-64 4.5.4 C:\Programs\mingw64\
Cygwin - C:\Programs\cygwin64\
SDL 1.2.15 C:\Programs\SDL\{x32|x64}\
cURL 7.64.1 C:\Programs\curl\{x32|x64}\
OpenSSL 1.1.1b C:\Programs\OpenSSL\{x32|x64}\
gSOAP 2.8.82 C:\Programs\gSOAP\
libvpx 1.7.0 C:\Programs\libvpx\
libopus 1.3 C:\Programs\libopus\
MiKTeX Portable 2.9.6942 C:\Programs\MiKTeX\
NASM 2.14.02 x64 C:\Programs\nasm\
DocBook XML DTD 4.5 C:\Programs\DocBook\xml\
DocBook XSL Stylesheets 1.69.1 C:\Programs\DocBook\xsl\

 Особенности установки программ


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

• Windows SDK v7.1
При установке могут возникнуть проблемы из-за устаревших версий компиляторов и рантайма: они не могут установиться поверх более новых версий, установленных с VS 2010, и инсталлятор считает это критической ошибкой. Необходимо либо отключить соответствующие галочки, либо предварительно удалить из системы пакеты с именами вида «Microsoft Visual C++ 2010 <arch> Redistributable», «Microsoft Visual C++ 2010 <arch> Runtime», «Microsoft Visual C++ Compilers…» (SDK установит старые версии пакетов, а Windows Update потом обновит их до актуальных).

Также обратите внимание, что для финальной сборки MSI-пакетов потребуется установить примеры программ (Windows Native Code Development -> Samples): в их составе идут скрипты, использующиеся сборочными правилами.

• Windows SDK v8.1
Достаточно установить только средства разработки (Windows Software Development Kit).

• WDK v7.1
Достаточно установить только сборочные окружения (Build Environments).

• Qt 5.6.3
Начиная с версии Qt 5.7.0 прекращена поддержка сборки в MSVC версий ниже 2012, поэтому используем 5.6.x.
Для Visual Studio 2010 официальные сборки отсутствуют, поэтому необходимо сначала собрать библиотеку из исходных кодов.

  1. Распаковываем архив с исходным кодом Qt в каталог C:\Programs\Qt\ и переименовываем полученный подкаталог qt-everywhere-opensource-src-5.6.3 в 5.6.3-src.
  2. Рядом создаём каталог build-x32, в котором будет происходить сборка.
  3. Открываем консоль, выполняем следующие команды для подготовки окружения:
    cd /d C:\Programs\Qt\build-x32
    SET QTVER=5.6.3
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x86 /win7
    COLOR 07
    SET QTDIR=C:\Programs\Qt\%QTVER%-x32
    SET PATH=%QTDIR%\bin;%PATH%
    SET QMAKESPEC=win32-msvc2010
    Команда color отключает зелёный цвет шрифта, устанавливаемый скриптом SetEnv.Cmd.
  4. Теперь запускаем configure.bat из каталога 5.6.3-src. Поскольку бо́льшая часть Qt в VB не используется, можно сильно ускорить сборку, отключив ненужные компоненты, но необходимо учитывать, что к некоторым опциям VB относится очень щепетильно. В частности, я наткнулся на следующее:
    • OpenGL ES 2 не поддерживается (компиляция VB не может увидеть некоторые заголовочные файлы).
    • Поддержка FreeType должна быть включена (без неё не соберётся плагин qoffscreen, использующийся в VB).
    Вот итоговая команда, которую я использовал у себя:
    ..\5.6.3-src\configure.bat -prefix c:\Programs\Qt\5.6.3-x32 -mp -opensource -confirm-license -nomake tests -nomake examples -no-compile-examples -release -shared -pch -no-ltcg -accessibility -no-sql-sqlite -opengl desktop -no-openvg -no-nis -no-iconv -no-evdev -no-mtdev -no-inotify -no-eventfd -largefile -no-system-proxies -qt-zlib -qt-pcre -no-icu -qt-libpng -qt-libjpeg -qt-freetype -no-fontconfig -qt-harfbuzz -no-angle -incredibuild-xge -no-plugin-manifests -qmake -qreal double -rtti -strip -no-ssl -no-openssl -no-libproxy -no-dbus -no-audio-backend -no-wmf-backend -no-qml-debug -no-direct2d -directwrite -no-style-fusion -native-gestures -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtconnectivity -skip qtdeclarative -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmacextras -skip qtmultimedia -skip qtquickcontrols -skip qtquickcontrols2 -skip qtscript -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns
  5. Указанный каталог установки (опция -prefix) Qt записывает внутрь генерируемых промежуточных файлов исходного кода при конфигурировании, так что собранная библиотека будет помнить этот путь. Это приводит к тому, что при запуске Qt-приложение по умолчанию будет искать плагины по этому пути, и только если ничего не нашлось, обратится к собственному каталогу. В большинстве ситуаций это работает корректно, но если вдруг на целевой машине в каталоге c:\Programs\Qt\5.6.3-x32 окажется отличающаяся сборка Qt (с другими флагами), то VB при запуске свалится с ошибкой.
    Избежать этого можно двумя путями: либо добавить в каталог VB файл qt.conf с содержимым:
    [Paths]
    Plugins=.
    либо подправить сохранённый в Qt путь установки, чтобы он по умолчанию указывал на каталог программы. Я пошёл по второму пути, чтобы итоговая установка VB выглядела более аккуратной. Для этого нужно открыть файл C:\Programs\Qt\build-x32\qtbase\src\corelib\global\qconfig.cpp, который создался конфигуратором, найти там строчку вида:
    static const char qt_configure_prefix_path_str       [512 + 12] = "qt_prfxpath=c:/Programs/Qt/5.6.3-x32";
    и заменить там весь путь на точку, чтобы получилось следующее:
    static const char qt_configure_prefix_path_str       [512 + 12] = "qt_prfxpath=.";
    Установка Qt при этом по-прежнему будет выполнена в указанный ранее каталог, потому что он уже сохранён в Makefile-ах. Это изменение затронет только поведение Qt-программ при их запуске.
  6. Далее запускаем сборку командой nmake
  7. Устанавливаем скомпилированную библиотеку командой nmake install

Теперь открываем новую консоль и аналогичным образом компилируем и устанавливаем 64-битную версию, только в именах каталогов необходимо заменить «x32» на «x64», а команды создания окружения будут выглядеть так:
md C:\Programs\Qt\build-x64
cd /d C:\Programs\Qt\build-x64
SET QTVER=5.6.3
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 /win7
COLOR 07
SET QTDIR=C:\Programs\Qt\%QTVER%-x64
SET PATH=%QTDIR%\bin;%PATH%
SET QMAKESPEC=win32-msvc2010

После завершения установки каталоги build-x32, build-x64 и 5.6.3-src можно удалять.

• MinGW
Архивы 32- и 64-битной версий просто распаковываются каждый в свой каталог.

• Cygwin
При установке необходимо отметить пакеты make и yasm.

• SDL
  1. Распаковываем SDL два раза в отдельные каталоги: C:\Programs\SDL\x32\ и C:\Programs\SDL\x64\.
  2. Перемещаем всё содержимое C:\Programs\SDL\x64\lib\x64\ на уровень выше (в C:\Programs\SDL\x64\lib\), каталоги C:\Programs\SDL\x64\lib\x86 и x64 удаляем.
  3. Аналогично для 32-битной версии: перемещаем содержимое C:\Programs\SDL\x32\lib\x86\ на уровень выше, каталоги C:\Programs\SDL\x32\lib\x86 и x64 удаляем.

• NASM
Распаковываем архив nasm-2.14.02-win64.zip в C:\Programs\, переименовываем полученный каталог nasm-2.14.02 в nasm.

• OpenSSL
  1. Распаковываем архив OpenSSL два раза в каталог C:\Programs\OpenSSL\, переименовывая полученный подкаталог из openssl-1.1.1b, соответственно, в openssl-1.1.1b-x32 и openssl-1.1.1b-x64.
  2. Открываем консоль, собираем и устанавливаем 32-битную версию:
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x86 /win7
    COLOR 07
    set PATH=%PATH%;C:\Programs\nasm
    cd /d C:\Programs\OpenSSL\openssl-1.1.1b-x32\
    perl Configure VC-WIN32 no-shared --prefix=C:\Programs\OpenSSL\x32 --openssldir=C:\Programs\OpenSSL\x32\ssl
    nmake
    nmake test
    nmake install
    Конфигуратор может выдать страшное сообщение, что, дескать, не может найти компилятор. Не обращайте внимания, это он слегка не в себе.
    Если вы не хотите использовать NASM, исключите отсюда модификацию переменной PATH и добавьте к вызову Configure параметр no-asm.
  3. Открываем новую консоль, собираем и устанавливаем 64-битную версию:
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 /win7
    COLOR 07
    set PATH=%PATH%;C:\Programs\nasm
    cd /d C:\Programs\OpenSSL\openssl-1.1.1b-x64\
    perl Configure VC-WIN64A no-shared --prefix=C:\Programs\OpenSSL\x64 --openssldir=C:\Programs\OpenSSL\x64\ssl
    nmake
    nmake test
    nmake install
    Отказ от NASM делается аналогично 32-битной версии.
  4. Каталоги C:\Programs\OpenSSL\openssl-1.1.1b-x32 и openssl-1.1.1b-x64 можно удалять.

• cURL
  1. Распаковываем архив cURL в каталог C:\Programs\curl\, переименовываем получившийся подкаталог из curl-7.64.1 в curl-7.64.1-x32.
  2. Открываем в редакторе файл C:\Programs\curl\curl-7.64.1-x32\winbuild\MakefileBuild.vc, находим там в районе строк 61–69 условный блок вида:
    !IF "$(VC)"=="6"
    CC_NODEBUG  = $(CC) /O2 /DNDEBUG
    CC_DEBUG    = $(CC) /Od /Gm /Zi /D_DEBUG /GZ
    CFLAGS      = /I. /I../lib /I../include /nologo /W4 /wd4127 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL
    !ELSE
    CC_NODEBUG  = $(CC) /O2 /DNDEBUG
    CC_DEBUG    = $(CC) /Od /D_DEBUG /RTC1 /Z7 /LDd
    CFLAGS      = /I. /I ../lib /I../include /nologo /W4 /wd4127 /EHsc /DWIN32 /FD /c /DBUILDING_LIBCURL
    !ENDIF
    и добавляем после него строчку:
    CFLAGS      = $(CFLAGS) /DCURL_DISABLE_LDAP
    Если этого не сделать, то при сборке VB полезут ошибки линковки.
  3. Открываем файл C:\Programs\curl\curl-7.64.1-x32\winbuild\gen_resp_file.bat, после первой строчки в нём (@echo OFF) вставляем команду:
    cd .
    Это фиктивная команда, которая ничего не делает, и задача её лишь в том, чтобы сбросить код ERRORLEVEL. В противном случае может возникнуть ситуация, когда этот код оказывается ненулевым ещё до запуска батника, а сам батник не выполняет ни одной команды, меняющей код возврата. В результате nmake считает, что батник вернул ошибку, и прерывает сборку.
  4. Делаем копию каталога curl-7.64.1-x32 под именем curl-7.64.1-x64.
  5. Открываем консоль, собираем 32-битную версию и копируем необходимые файлы в целевой каталог:
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x86 /win7
    COLOR 07
    cd /d C:\Programs\curl\curl-7.64.1-x32\winbuild
    md C:\Programs\curl\x32
    nmake /f Makefile.vc mode=static WITH_SSL=static DEBUG=no MACHINE=x86 SSL_PATH=C:\Programs\OpenSSL\x32 ENABLE_SSPI=no ENABLE_WINSSL=no ENABLE_IDN=no
    copy ..\builds\libcurl-vc-x86-release-static-ssl-static-ipv6\lib\libcurl_a.lib ..\..\x32\libcurl.lib
    xcopy /E ..\builds\libcurl-vc-x86-release-static-ssl-static-ipv6\include\curl ..\..\x32\include\curl\
  6. Собираем 64-битную версию, открыв новую консоль и выполнив команды:
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 /win7
    COLOR 07
    cd /d C:\Programs\curl\curl-7.64.1-x64\winbuild
    md C:\Programs\curl\x64
    nmake /f Makefile.vc mode=static WITH_SSL=static DEBUG=no MACHINE=x64 SSL_PATH=C:\Programs\OpenSSL\x64 ENABLE_SSPI=no ENABLE_WINSSL=no ENABLE_IDN=no
    copy ..\builds\libcurl-vc-x64-release-static-ssl-static-ipv6\lib\libcurl_a.lib ..\..\x64\libcurl.lib
    xcopy /E ..\builds\libcurl-vc-x64-release-static-ssl-static-ipv6\include\curl ..\..\x64\include\curl\
    copy ..\builds\libcurl-vc-x64-release-static-ssl-static-ipv6\bin\curl.exe ..\..\x64\curl.exe
    Обратите внимание, что, в отличие от 32-битной версии, здесь мы копируем ещё и curl.exe, он нам потом понадобится для скачивания образа гостевых дополнений.
  7. Каталоги C:\Programs\curl\curl-7.64.1-x32 и curl-7.64.1-x64 можно удалять.

• libvpx
  1. Распаковываем архив libvpx в каталог C:\Programs\libvpx-build\.
  2. Запускаем Cygwin, в нём будем выполнять конфигурирование, сборку и установку библиотеки. В качестве целевой платформы будет указана Visual Studio 2010. При этом сборочная система попытается автоматически запустить сборку, но будет делать это с использованием msbuild.exe, который мне не удалось заставить работать корректно в имеющемся окружении. Вместо этого оказалось проще запустить отдельным шагом сборку самой Студией, благо она позволяет работать из командной строки. Впрочем, можно этот шаг выполнить и при помощи графической среды, если кому-то она привычнее, но в этом случае вам придётся к переменной PATH добавить путь C:\Programs\cygwin64\bin (или как-то иначе задать его в проекте), потому что там располагается ассемблер yasm.exe, необходимый для сборки. Итак, в терминале Cygwin выполняем следующие команды:
    mkdir -p /cygdrive/c/Programs/libvpx-build/build32
    cd /cygdrive/c/Programs/libvpx-build/build32
    ../libvpx-1.7.0/configure --target=x86-win32-vs10 --disable-install-bins --disable-examples --disable-tools --disable-docs --prefix=../../libvpx
    make
    "/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 10.0/Common7/IDE/devenv.com" vpx.sln /Project vpx.vcxproj /Rebuild "Release|Win32"
    make install
    
    mkdir -p /cygdrive/c/Programs/libvpx-build/build64
    cd /cygdrive/c/Programs/libvpx-build/build64
    ../libvpx-1.7.0/configure --target=x86_64-win64-vs10 --disable-install-bins --disable-examples --disable-tools --disable-docs --prefix=../../libvpx
    make
    "/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 10.0/Common7/IDE/devenv.com" vpx.sln /Project vpx.vcxproj /Rebuild "Release|x64"
    make install
  3. Закрываем терминал Cygwin, больше он нам не понадобится. Каталог C:\Programs\libvpx-build можно удалять.

• libopus
  1. Распаковываем архив opus в каталог C:\Programs\libopus-build\, переходим в подкаталог opus-1.3\win32\VS2015.
  2. Проект рассчитан на более новую версию Visual Studio, и в 2010-й просто так не соберётся, надо внести немножко правок. Можно это сделать как через IDE, так в обычном текстовом редакторе. Я предпочёл второй путь. Итак, открываем в редакторе файл opus.vcxproj (остальные проекты нам не нужны) и проделываем следующие манипуляции:
    1. Находим все строки с текстом
      <PlatformToolset>v140</PlatformToolset>
      и меняем версию с v140 на v100. Если вы работаете в IDE, то эта опция в настройках проекта располагается на странице Configuration Properties -> General и называется «Platrofm Toolset». Не забудьте выбрать конфигурации и архитектуры в выпадающих списках в верхней части диалога.
    2. Далее находим блок:
        <ItemDefinitionGroup>
          <ClCompile>
      и добавляем туда тег:
            <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      В настройках проекта Visual Studio это делается на странице Configuration Properties -> C/C++ -> General выставлением опции «Debug Information Format» в «ProgramDatabase (/Zi)». Собственно говоря, подойдёт и любое другое валидное значение из списка, база отладочной информации нас не интересует, просто при невалидном значении проект отказывается собираться.
  3. Теперь собираем Release-конфигурацию для обеих архитектур (из оболочки VS или из командной строки) и копируем собранную библиотеку opus.lib и подкаталог include\ в целевой каталог установки:
    cd /d C:\Programs\libopus-build\opus-1.3\win32\VS2015
    md C:\Programs\libopus\lib\x64
    md C:\Programs\libopus\lib\Win32
    xcopy /E C:\Programs\libopus-build\opus-1.3\include C:\Programs\libopus\include\
    
    "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com" opus.sln /Project opus.vcxproj /Rebuild "Release|x64"
    copy x64\Release\opus.lib C:\Programs\libopus\lib\x64\
    
    "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com" opus.sln /Project opus.vcxproj /Rebuild "Release|Win32"
    copy Win32\Release\opus.lib C:\Programs\libopus\lib\Win32\
  4. Каталог C:\Programs\libopus-build можно удалять.

• gSOAP
Открываем архив, заходим в подкаталог gsoap-2.8\gsoap и распаковываем содержимое этого подкаталога в C:\Programs\gSOAP\. Для корректной сборки с OpenSSL 1.1.x требуется версия 2.8.41 или выше. Для более ранних версий потребуется наложить специальный патч (автор: Mattias Ellert). Можно это сделать вручную (формат достаточно очевидный: открываем поочерёдно указанные файлы, удаляем строчки, отмеченные минусами, и добавляем отмеченные плюсами; остальные строки помогают определить контекст), а можно взять стандартную утилиту patch, портированную для Windows, и натравить её.

• MiKTeX
  1. Распаковываем архив в C:\Programs\MiKTeX\.
  2. Открываем консоль и запускаем установку дополнительных модулей:
    "C:\Programs\MiKTeX\texmfs\install\miktex\bin\mpm.exe" --verbose --install=koma-script --install=ucs --install=tabulary --install=url --install=fancybox --install=fancyvrb --install=bera --install=charter --install=mptopdf

• DocBook
Для распаковки архива XML DTD нужно создать отдельный каталог и поместить туда все файлы. Архив с XSL Stylesheets уже содержит нужный подкаталог, поэтому достаточно его просто распаковать и переименовать полученный подкаталог.

 Последние штрихи


Подготовка к сборке почти завершена, остались несколько шагов. Если вы этого ещё не сделали, нужно скачать архив с исходными кодами VirtualBox нужной версии и распаковать его в удобное место. В качестве рабочего каталога я выбрал C:\Devel\; в него я распаковал архив исходных кодов и переименовал полученный каталог в VirtualBox-src.

• Добавление сертификатов

Если у вас нет полноценного сертификата, то рекомендуется создать хотя бы персональный (с ним проще загружать драйверы, чем совсем без подписи). Для этого нужно открыть консоль с повышенными привилегиями и выполнить в ней следующие команды, которые создадут и добавят в личное хранилище два сертификата (SHA-1 и SHA-256):
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 /win7
COLOR 07
makecert.exe -a sha1 -r -pe -ss my -n "CN=Roga and Kopyta Ltd" C:\Devel\testcert_1.cer
makecert.exe -a sha256 -r -pe -ss my -n "CN=Roga and Kopyta Ltd" C:\Devel\testcert_256.cer
certmgr.exe -add C:\Devel\testcert_1.cer -s -r localMachine root
certmgr.exe -add C:\Devel\testcert_256.cer -s -r localMachine root
Имя для сертификатов («Roga and Kopyta Ltd») и путь к файлам можно выбирать по своему усмотрению. Также нам потребуются цифровые отпечатки сгенерированных сертификатов. Откройте консоль управления сертификатами (запустите certmgr.msc), откройте там список персональных сертификатов. Дважды щёлкните на первом из сертификатов «Roga and Kopyta Ltd», в открывшемся диалоге перейдите на вкладку Состав. В поле «Алгоритм подписи» будет указано sha256RSA или sha1RSA. Далее, в самом конце списка будет поле «Отпечаток» со значением в виде последовательности шестнадцатеричных чисел. Скопируйте это значение куда-нибудь. То же самое повторите для второго из сертификатов. Не забудьте отметить, какой из них был SHA-256, а какой — SHA-1.

• Сборка xmllint

На одном из этапов потребуется также программа xmllint. Я не указывал её в списке требований, потому что необходимые исходники уже присутствуют в архиве VB. Сборочные правила не рассчитаны на автоматическую сборку этой утилиты, поэтому придётся сделать это самостоятельно. В качестве целевого каталога я выбрал C:\Programs\xmllint.
  1. Копируем каталог C:\Devel\VirtualBox-src\src\libs\libxml2-2.9.4 в C:\Programs\ (это необходимо, чтобы промежуточные объектные файлы не мешали сборке самого VB).
  2. Открываем консоль и выполняем команды:
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 /win7
    COLOR 07
    cd /d C:\Programs\libxml2-2.9.4\win32
    cscript.exe configure.js cruntime=/MT prefix=C:\Programs\xmllint iconv=no
    nmake /f Makefile.msvc
    nmake /f Makefile.msvc install
  3. Удаляем каталог C:\Programs\libxml2-2.9.4.

• Различные правки VB

Прежде чем приступать к сборке, нам ещё потребуется внести кое-какие правки в исходные коды самого VirtualBox. Полный набор всех изменений выложен мной в виде отдельного патча, который можно просто наложить целиком на дерево VB (вручную или используя утилиту patch, которую потребуется скачать отдельно):

» vbox_build.patch

Если всё наложилось корректно, то можно переходить к следующему пункту. Если же что-то не состыковалось и требуется разобраться с конкретным изменением, или просто вас интересуют подробности, какие именно правки были внесены и зачем, читайте далее. Имейте в виду, что описания здесь могут идти в не в том порядке, как в патче. Пути к файлам указаны относительно каталога с исходниками VB, C:\Devel\VirtualBox-src.
  1. Файл configure.vbs:
    • Строка кода:
      if Shell(DosSlashes(strPathVC & "/bin/cl.exe"), True) <> 0 then
      заменяется на:
      if Shell(DosSlashes(strPathVC & "/bin/cl.exe") & " /?", True) <> 0 then
      Этот код отвечает за поиск и проверку компилятора, но не учитывает, что вызов cl.exe без аргументов возвращает ошибку (что трактуется как неподходящий компилятор). Добавление параметра «/?» запрашивает вывод справки, и код возврата перестаёт быть ошибочным.
    • Теперь переходим к функции CheckForMinGW32Sub. Здесь проверяется корректность 32-битного MinGW с расчётом на версию 3.3.3. У нас используется версия 4.5.4, где структура файлов/каталогов довольно сильно отличается, поэтому вся функция заменяется на следующий код (я его просто перенёс из CheckForMinGWw64Sub, немного адаптировав):
      function CheckForMinGW32Sub(strPathMingW32, strPathW32API)
         g_strSubOutput = ""
         if strPathW32API = "" then strPathW32API = strPathMingW32
         LogPrint "trying: strPathMingW32="  &strPathMingW32 & " strPathW32API=" & strPathW32API
      
         if   LogFileExists(strPathMingW32, "bin/gcc.exe") _
          And LogFileExists(strPathMingW32, "bin/ld.exe") _
          And LogFileExists(strPathMingW32, "bin/objdump.exe") _
          And LogFileExists(strPathMingW32, "bin/dllwrap.exe") _
          And LogFileExists(strPathMingW32, "bin/dlltool.exe") _
          And LogFileExists(strPathMingW32, "bin/as.exe") _
          And LogFileExists(strPathMingW32, "include/bfd.h") _
          And LogFileExists(strPathMingW32, "lib32/libgcc_s.a") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/lib/dllcrt1.o") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/lib/dllcrt2.o") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/lib/libmsvcrt.a") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/lib/libmsvcr100.a") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/include/_mingw.h") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/include/stdint.h") _
          And LogFileExists(strPathMingW32, "i686-w64-mingw32/include/windows.h") _
            then
            if Shell(DosSlashes(strPathMingW32 & "/bin/gcc.exe") & " -dumpversion", True) = 0 then
               dim offVer, iMajor, iMinor, iPatch, strVer
      
               ' extract the version.
               strVer = Trim(Replace(Replace(g_strShellOutput, vbCr, ""), vbLf, ""))
               if   (Mid(strVer, 2, 1) = ".") _
                And (Mid(strVer, 4, 1) = ".") then
                  iMajor = Int(Left(strVer, 1)) ' Is Int() the right thing here? I want atoi()!!!
                  iMinor = Int(Mid(strVer, 3, 1))
                  iPatch = Int(Mid(strVer, 5))
               else
                  LogPrint "Malformed version: '" & strVer & "'"
                  strVer = ""
               end if
               if strVer <> "" then
                  if (iMajor = 4) And (iMinor >= 4) then
                     CheckForMinGW32Sub = True
                     g_strSubOutput = strVer
                  else
                     LogPrint "MinGW32 version '" & iMajor & "." & iMinor & "." & iPatch & "' is not supported (or configure.vbs failed to parse it correctly)."
                  end if
               else
                  LogPrint "Couldn't locate the GCC version in the output!"
               end if
      
            else
               LogPrint "Failed to run gcc.exe!"
            end if
         end if
      end function
    • Следующая функция — CheckForCurlSub, в ней — вот такой код:
         if   LogFileExists(strPathCurl, "include/curl/curl.h") _
          And LogFindFile(strPathCurl, "libcurl.dll") <> "" _
          And LogFindFile(strPathCurl, "libcurl.lib") <> "" _
      Этот код выполняет поиск и проверку пути к libcurl, но он рассчитан только на использование динамически линкуемой версии библиотеки и, если не находит соответствующий DLL-файл, ругается некультурными словами. Поскольку мы собираем со статической версией, эту проверку надо поправить, удалив строчку с libcurl.dll, чтобы получилось:
         if   LogFileExists(strPathCurl, "include/curl/curl.h") _
          And LogFindFile(strPathCurl, "libcurl.lib") <> "" _
    • Теперь переходим к функции CheckForPython, там есть генерация переменной VBOX_BLD_PYTHON:
            CfgPrint "VBOX_BLD_PYTHON       := " & strPathPython & "\python.exe"
      Здесь нужно обратный слэш перед python.exe заменить на прямой: "/python.exe" (иначе некоторые проверки падают; вроде бы, для сборки это некритично, но выглядит неаккуратно).
    • В Windows-версии конфигуратор не поддерживает libvpx и libopus, я добавляю их поддержку самостоятельно. Можно было, конечно, просто прохардкодить пути установки библиотек, но я предпочёл, чтобы конфигуратор проверял корректность установки и принимал путь через аргументы командной строки, как уже сделано для остальных компонентов. Поэтому я реализовал две проверочные функции, выглядящие следующим образом:
      ''
      ' Checks for libvpx
      sub CheckForVpx(strOptVpx)
         dim strPathVpx, str
         strVpx = "libvpx"
         PrintHdr strVpx
      
         if strOptVpx = "" then
            MsgError "Invalid path specified!"
            exit sub
         end if
      
         if g_strTargetArch = "amd64" then
            strVsBuildArch = "x64"
         else
            strVsBuildArch = "Win32"
         end if
         strLibPathVpx = "lib/" & strVsBuildArch & "/vpxmd.lib"
      
         strPathVpx = ""
         if   LogFileExists(strOptVpx, "include/vpx/vpx_encoder.h") _
          And LogFileExists(strOptVpx, strLibPathVpx) _
            then
               strPathVpx = UnixSlashes(PathAbs(strOptVpx))
               CfgPrint "SDK_VBOX_VPX_INCS := " & strPathVpx & "/include"
               CfgPrint "SDK_VBOX_VPX_LIBS := " & strPathVpx & "/" & strLibPathVpx
            else
               MsgError "Can't locate " & strVpx & ". " _
                      & "Please consult the configure.log and the build requirements."
               exit sub
            end if
      
         PrintResult strVpx, strPathVpx
      end sub
      
      
      
      ''
      ' Checks for libopus
      sub CheckForOpus(strOptOpus)
         dim strPathOpus, str
         strOpus = "libopus"
         PrintHdr strOpus
      
         if strOptOpus = "" then
            MsgError "Invalid path specified!"
            exit sub
         end if
      
         if g_strTargetArch = "amd64" then
            strVsBuildArch = "x64"
         else
            strVsBuildArch = "Win32"
         end if
         strLibPathOpus = "lib/" & strVsBuildArch & "/opus.lib"
      
         strPathOpus = ""
         if   LogFileExists(strOptOpus, "include/opus.h") _
          And LogFileExists(strOptOpus, strLibPathOpus) _
            then
               strPathOpus = UnixSlashes(PathAbs(strOptOpus))
               CfgPrint "SDK_VBOX_OPUS_INCS := " & strPathOpus & "/include"
               CfgPrint "SDK_VBOX_OPUS_LIBS := " & strPathOpus & "/" & strLibPathOpus
            else
               MsgError "Can't locate " & strOpus & ". " _
                      & "Please consult the configure.log and the build requirements."
               exit sub
            end if
      
         PrintResult strOpus, strPathOpus
      end sub
      Далее в функции usage, где печатается справка по аргументам, приписывается вывод двух свежедобавленных:
         Print "  --with-libvpx=PATH    "
         Print "  --with-libopus=PATH   "
      В начале функции Main находятся переменные, хранящие всевозможные пути к программам и библиотекам — там создаются две новых переменных:
         strOptVpx = ""
         strOptOpus = ""
      Ниже идёт блок select-case с обработкой параметров командной строки, здесь добавляется код для двух новых аргументов:
               case "--with-libvpx"
                  strOptVpx = strPath
               case "--with-libopus"
                  strOptOpus = strPath
      И наконец, практически в конце файла идёт цепочка вызовов всех проверочных функций, отвечающих за разные компоненты, и туда вписываются вызовы наших новых обработчиков:
         CheckForVpx strOptVpx
         CheckForOpus strOptOpus
  2. Следующий файл — src\VBox\Runtime\Makefile.kmk. Находим там определения переменных VBoxRT_LIBS.win и VBoxRT-x86_LIBS.win и добавляем к ним crypt32.lib и bcrypt.lib. А именно, код:
    VBoxRT_LIBS.win                = \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB)/vccomsup.lib \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB)/wbemuuid.lib \
    	$(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/delayimp.lib
    заменяется на:
    VBoxRT_LIBS.win                = \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB)/vccomsup.lib \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB)/wbemuuid.lib \
    	$(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/delayimp.lib \
    	$(PATH_SDK_$(VBOX_WINPSDK)_LIB)/crypt32.lib \
    	$(PATH_SDK_$(VBOX_WINPSDK)_LIB)/bcrypt.lib
    (не пропустите обратный слэш после delayimp.lib!); и аналогично:
    VBoxRT-x86_LIBS.win                = \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB.x86)/vccomsup.lib \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB.x86)/wbemuuid.lib \
    	$(PATH_TOOL_$(VBOX_VCC_TOOL_STEM)X86_LIB)/delayimp.lib
    заменяется на:
    VBoxRT-x86_LIBS.win                = \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB.x86)/vccomsup.lib \
    	$(PATH_SDK_$(VBOX_WINDDK)_LIB.x86)/wbemuuid.lib \
    	$(PATH_TOOL_$(VBOX_VCC_TOOL_STEM)X86_LIB)/delayimp.lib \
    	$(PATH_SDK_$(VBOX_WINPSDK)_LIB.x86)/crypt32.lib \
    	$(PATH_SDK_$(VBOX_WINPSDK)_LIB.x86)/bcrypt.lib
    Это требуется для успешной линковки библиотеки VBoxRT.dll. Я не до конца разобрался в этой особенности: в дистрибутиве Oracle нет зависимости от библиотеки crypt32.dll, она там загружается динамически во время выполнения, поэтому, теоретически, LIB-файл добавлять не нужно. Однако если этого не сделать, линковщик не может найти некоторые функции и отказывается собирать библиотеку. Предполагаю, что это как-то связано с опциями сборки OpenSSL, но детально не разбирался, проще было добавить эту библиотеку в список. А зависимость от bcrypt.dll появилась при переходе на OpenSSL 1.1.1.
  3. Если вы используете gSOAP версии 2.8.79 или выше, то требуется подправить файл src\VBox\Runtime\r3\win\VBoxRT-openssl-1.1plus.def, добавив куда-нибудь в общий список следующий набор строк:
        OpenSSL_version_num
        DH_generate_parameters_ex
        DH_new
        ASN1_STRING_get0_data
    Этот список определяет набор функций, экспортируемых библиотекой VBoxRT.dll, включающей в себя OpenSSL. При линковке утилиты VBoxWebSrv.exe, в зависимости от используемой версии gSOAP, этих экспортов может оказаться недостаточно, и тогда линковщик дополнительно подключает OpenSSL и тут же начинает материться из-за того, что эта внешняя OpenSSL начинает драться со своей копией, внедрённой внутрь VBoxRT. Добавление отсутствующих экспортов устраняет эту проблему.
  4. Как я упомянул в начале статьи, сборку гостевых дополнений я пропускаю, но их ISO-образ в составе дистрибутива должен присутствовать. Сборочные файлы VB на такую конструкцию в целом рассчитаны, но они ожидают, что сам ISO-файл магическим образом появится в нужном месте в нужное время. У меня эта магия реализована в файле src\VBox\Makefile.kmk. Находим там блок кода вида:
      ifdef VBOX_WITH_ADDITIONS
       include $(PATH_SUB_CURRENT)/Additions/Makefile.kmk
      endif
    и после него добавляем определение сборочного правила для загрузки образа:
     ifndef VBOX_WITHOUT_ADDITIONS_ISO
      $(VBOX_PATH_ADDITIONS_ISO)/VBoxGuestAdditions.iso:
    	$(QUIET)$(MKDIR) -p $(@D)
    	$(VBOX_RETRY) $(TOOL_CURL_FETCH) http://download.virtualbox.org/virtualbox/$(VBOX_VERSION_STRING_RAW)/VBoxGuestAdditions_$(VBOX_VERSION_STRING_RAW).iso -o $@
     endif
    Если вы правите файлы самостоятельно, а не готовым патчем, учтите, что строки-команды должны начинаться с символа табуляции.
  5. Сборка документации была существенно переделана в версии 6.0, и если раньше всё собиралось без каких-либо доработок, то теперь приходится лезть и в эту подсистему. Я не знаю, в каких условиях документация собирается в Oracle (возможно, они используют *NIX-подобную систему), но у меня различные компоненты то и дело теряли слэши в путях или, наоборот, получали лишние, и в итоге не могли найти нужные файлы из-за сбившихся соответствий в каталожных файлах. Методом научного тыка мне удалось в итоге подобрать комбинацию, с которой документация собралась без ошибок. В первую очередь была исправлена ошибка отсутствия одного из промежуточных целевых каталогов, из-за чего некоторые файлы не могли быть созданы. Это делается в файле doc\manual\Makefile.kmk в блоке кода:
    define def_vbox_refentry_to_user_sect1
    $$(VBOX_PATH_MANUAL_OUTBASE)/$(1)/user_$(2): $(3) \
    		$$(VBOX_PATH_MANUAL_SRC)/docbook-refentry-to-manual-sect1.xsl \
    		$$(VBOX_XML_CATALOG) $$(VBOX_XML_CATALOG_DOCBOOK) $$(VBOX_XML_CATALOG_MANUAL) \
    		$$(VBOX_VERSION_STAMP) | $$(dir $$@)
    	$$(call MSG_TOOL,xsltproc $$(notdir $$(filter %.xsl,$$^)),,$$(filter %.xml,$$^),$$@)
    	$$(QUIET)$$(RM) -f "$$@"
    	$$(QUIET)$$(call VBOX_XSLTPROC_WITH_CAT) --output $$@ $$(VBOX_PATH_MANUAL_SRC)/docbook-refentry-to-manual-sect1.xsl $$<
    endef
    Здесь после строчки с $$(RM) я добавил команду создания целевого каталога:
    	$$(QUIET)$$(MKDIR) -p "$$(@D)"

    Битва со слэшами происходит в файле doc\manual\Config.kmk. Нормального решения проблемы мне найти не удалось, поэтому в качестве обходного пути я просто добавил инструкции для обработки «кривых» путей. Сначала после строки:
      VBOX_FILE_URL_MAYBE_SLASH = $(if $(eq $(KBUILD_HOST),win),/,)
    я создаю две новых переменных, которые дублируют существующие переменные, но превращают одиночный слэш после имени диска в тройной:
     VBOX_PATH_MANUAL_SRC_SLASHED = $(subst :/,:///,$(VBOX_PATH_MANUAL_SRC))
     VBOX_PATH_MANUAL_OUTBASE_SLASHED = $(subst :/,:///,$(VBOX_PATH_MANUAL_OUTBASE))
    Чуть ниже находится правило для создания каталожного файла:
     $(VBOX_XML_CATALOG): $(MAKEFILE_CURRENT) | $$(dir $$@)
    	$(call MSG_L1,Creating catalog $@)
    	$(QUIET)$(APPEND) -tn "$@" \
    		'<?xml version="1.0"?>' \
    		'<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">' \
    		'<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">' \
    		'  <delegatePublic publicIdStartString="-//OASIS/ENTITIES DocBook XML"      catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegatePublic publicIdStartString="-//OASIS/DTD DocBook XML"           catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegateSystem systemIdStartString="http://www.oasis-open.org/docbook/" catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegateURI uriStartString="http://www.oasis-open.org/docbook/"         catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegateSystem systemIdStartString="$(VBOX_PATH_MANUAL_SRC)"            catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="$(VBOX_PATH_MANUAL_SRC)"                    catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_PATH_MANUAL_SRC)" catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="$(VBOX_PATH_MANUAL_OUTBASE)"                catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'</catalog>'
    Для каждой строки, использующей переменные VBOX_PATH_MANUAL_SRC и VBOX_PATH_MANUAL_OUTBASE, я добавил такую же, но с заменой этих переменных на определённые выше (строчку с префиксом file:// можно пропустить). В итоге получилось:
     $(VBOX_XML_CATALOG): $(MAKEFILE_CURRENT) | $$(dir $$@)
    	$(call MSG_L1,Creating catalog $@)
    	$(QUIET)$(APPEND) -tn "$@" \
    		'<?xml version="1.0"?>' \
    		'<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">' \
    		'<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">' \
    		'  <delegatePublic publicIdStartString="-//OASIS/ENTITIES DocBook XML"      catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegatePublic publicIdStartString="-//OASIS/DTD DocBook XML"           catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegateSystem systemIdStartString="http://www.oasis-open.org/docbook/" catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegateURI uriStartString="http://www.oasis-open.org/docbook/"         catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_DOCBOOK)"/>' \
    		'  <delegateSystem systemIdStartString="$(VBOX_PATH_MANUAL_SRC)"            catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateSystem systemIdStartString="$(VBOX_PATH_MANUAL_SRC_SLASHED)"    catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="$(VBOX_PATH_MANUAL_SRC)"                    catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="$(VBOX_PATH_MANUAL_SRC_SLASHED)"            catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_PATH_MANUAL_SRC)" catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="$(VBOX_PATH_MANUAL_OUTBASE)"                catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'  <delegateURI uriStartString="$(VBOX_PATH_MANUAL_OUTBASE_SLASHED)"        catalog="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_XML_CATALOG_MANUAL)"/>' \
    		'</catalog>'
    Ещё ниже присутствует правило для генерации вспомогательного каталожного файла, начинающееся со строки:
     $(VBOX_XML_CATALOG_MANUAL): $(MAKEFILE_CURRENT) | $$(dir $$@)
    В нём выполняется аналогичная операция. Кроме этого, в начале файла идут несколько строчек, ссылающихся на файлы в подкаталоге common/:
    		'  <system systemId="$(VBOX_PATH_MANUAL_SRC)/common/oracle-accessibility-en.xml"            uri="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_PATH_MANUAL_SRC)/en_US/oracle-accessibility-en.xml"/>' \
    		'  <system systemId="$(VBOX_PATH_MANUAL_SRC)/common/oracle-support-en.xml"                  uri="file://$(VBOX_FILE_URL_MAYBE_SLASH)$(VBOX_PATH_MANUAL_SRC)/en_US/oracle-support-en.xml"/>' \
    С ними наблюдается обратная проблема — исчезновение слэшей после протокола. Это я смог обойти, поменяв целевой адрес (атрибут uri) на обычный путь вместо file-протокола, так что, с учётом предыдущей правки, эти строки превратились в следующий набор соответствий:
    		'  <system systemId="$(VBOX_PATH_MANUAL_SRC)/common/oracle-accessibility-en.xml"            uri="$(VBOX_PATH_MANUAL_SRC)/en_US/oracle-accessibility-en.xml"/>' \
    		'  <system systemId="$(VBOX_PATH_MANUAL_SRC_SLASHED)/common/oracle-accessibility-en.xml"          uri="$(VBOX_PATH_MANUAL_SRC)/en_US/oracle-accessibility-en.xml"/>' \
    		'  <system systemId="$(VBOX_PATH_MANUAL_SRC)/common/oracle-support-en.xml"                  uri="$(VBOX_PATH_MANUAL_SRC)/en_US/oracle-support-en.xml"/>' \
    		'  <system systemId="$(VBOX_PATH_MANUAL_SRC_SLASHED)/common/oracle-support-en.xml"                uri="$(VBOX_PATH_MANUAL_SRC)/en_US/oracle-support-en.xml"/>' \
  6. Если VB собирается с подписыванием, то для большинства исполняемых файлов выставляется флаг принудительной проверки подписи (опция компоновщика /IntegrityCheck). При наличии полноценного сертификата это не проблема. Однако если у вас самоподписанный сертификат, VB просто откажется запускаться после установки (даже в тестовом режиме). Я модифицировал файл Config.kmk таким образом, чтобы флаг добавлялся только при использовании полноценного сертификата (в качестве критерия «полноценности» я выбрал наличие кросс-сертификата в файле LocalConfig.kmk; см. ниже). Набор исправлений заключается в следующем.
    • Вставлен блок определения переменной VBOX_INTEGRITY_CHECK, которая будет использоваться вместо фиксированной опции:
      if defined(VBOX_SIGNING_MODE) && defined(VBOX_CROSS_CERTIFICATE_FILE)
      	VBOX_INTEGRITY_CHECK := /IntegrityCheck
      else
      	VBOX_INTEGRITY_CHECK := /IntegrityCheck:NO
      endif
    • Чуть ниже идёт вызов утилиты editbin:
      	$(VBOX_VCC_EDITBIN) /LargeAddressAware /DynamicBase /NxCompat /Release /IntegrityCheck \
      		/Version:$(VBOX_VERSION_MAJOR)0$(VBOX_VERSION_MINOR).$(VBOX_VERSION_BUILD) \
      		"$@"
      В нём безусловный /IntegrityCheck заменяется на новую переменную $(VBOX_INTEGRITY_CHECK).
    • Далее ищутся все вхождения следующего вида:
      ifdef VBOX_SIGNING_MODE
       TEMPLATE_XXXXXX_LDFLAGS          += -IntegrityCheck
      endif
      или
      if defined(VBOX_SIGNING_MODE) && defined(VBOX_WITH_HARDENING)
       TEMPLATE_XXXXXX_LDFLAGS          += -IntegrityCheck
      endif
      где вместо «XXXXXX» могут быть различные имена компонентов. Всего таких вхождений — 6 штук, по три каждого вида. Здесь добавляется условие, что переменная кросс-сертификата определена. В итоге первая строчка превращается, соответственно, в одну из нижеследующих:
      if defined(VBOX_SIGNING_MODE) && defined(VBOX_CROSS_CERTIFICATE_FILE)
      или
      if defined(VBOX_SIGNING_MODE) && defined(VBOX_CROSS_CERTIFICATE_FILE) && defined(VBOX_WITH_HARDENING)
  7. Ещё два файла, которые я поправил, не имеют прямого отношения к сборке VB. Это вспомогательные скрипты src\VBox\Installer\win\Scripts\PackDriversForSubmission.cmd и UnpackBlessedDrivers.cmd, которые можно использовать при отправке драйверов в Microsoft для подписывания их под Windows 10. Первый скрипт подготавливает CAB-архив для отправки, второй — распаковывает ответный ZIP-архив с подписанными драйверами и проверяет подписи. В PackDriversForSubmission.cmd поправлено несколько опечаток; в UnpackBlessedDrivers.cmd я добавил возможность задания пути к утилите signtool, а также избавился от утилиты unzip.exe, реализовав распаковку архива Perl-скриптом. О самой процедуре подписывания я расскажу чуть ниже. Если же вы не планируете получать подпись от Microsoft, то можете просто игнорировать эти правки.

• Файл конфигурации сборки VB

Осталось только создать в корне каталога с исходниками VB файл с именем LocalConfig.kmk, куда прописываются различные пути и параметры сборки. В качестве шаблона можно взять следующий код:
VBOX_WITH_HARDENING :=
VBOX_PATH_WIX := C:\Programs\WiX
VBOX_GSOAP_INSTALLED := 1
VBOX_PATH_GSOAP := C:\Programs\gSOAP
VBOX_WITH_COMBINED_PACKAGE := 1
VBOX_WITH_QT_PAYLOAD := 1
VBOX_WITH_QTGUI_V5 := 1
VBOX_SIGNING_MODE := release
VBOX_CERTIFICATE_SUBJECT_NAME := Roga and Kopyta Ltd
VBOX_CERTIFICATE_FINGERPRINT := XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
VBOX_CERTIFICATE_SHA2_SUBJECT_NAME := Roga and Kopyta Ltd
VBOX_CERTIFICATE_SHA2_FINGERPRINT := XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
VBOX_TSA_URL := http://timestamp.digicert.com
VBOX_TSA_SHA2_URL := http://timestamp.digicert.com
VBOX_TSA_URL_ARGS := /t "$(VBOX_TSA_URL)"
VBOX_TSA_SHA2_URL_ARGS := /tr "$(VBOX_TSA_SHA2_URL)" /td sha256
VBOX_CROSS_CERTIFICATE_FILE :=
VBOX_CROSS_CERTIFICATE_FILE_ARGS :=
VBOX_CROSS_CERTIFICATE_SHA2_FILE :=
VBOX_CROSS_CERTIFICATE_SHA2_FILE_ARGS :=
VBOX_PATH_SIGN_TOOLS := C:\Programs\DevKits\8.1\bin\x64
VBOX_PATH_SELFSIGN := C:\WinDDK\7600.16385.1\bin\selfsign
VBOX_PATH_WISUMINFO := "C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\sysmgmt\msi\scripts\WiSumInf.vbs"
VBOX_PATH_WISUBSTG  := "C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\sysmgmt\msi\scripts\WiSubStg.vbs"
VBOX_WITH_DOCS := 1
VBOX_WITH_DOCS_CHM := 1
VBOX_WITH_DOCS_PACKING := 1
VBOX_WITH_ADDITIONS :=
VBOX_WITH_ADDITIONS_PACKING := 1
VBOX_HAVE_XMLLINT := 1
VBOX_XMLLINT := C:\Programs\xmllint\bin\xmllint.exe
VBOX_PATH_DOCBOOK := C:/Programs/DocBook/xsl
VBOX_PATH_DOCBOOK_DTD := C:/Programs/DocBook/xml
VBOX_PATH_HTML_HELP_WORKSHOP := "C:\Program Files (x86)\HTML Help Workshop"
VBOX_PDFLATEX := C:\Programs\MiKTeX\texmfs\install\miktex\bin\pdflatex.exe
VBOX_PDFLATEX_CMD := $(VBOX_PDFLATEX) -halt-on-error -interaction batchmode
TOOL_CURL_FETCH := C:\Programs\curl\x64\curl.exe
PATH_TOOL_NASM := C:/Programs/nasm
VBOX_INSTALLER_LANGUAGES := en_US
VBOX_WITH_TESTCASES :=
VBOX_WITH_VALIDATIONKIT :=
VBOX_WITH_VBOX_IMG := 1
VBOX_WITH_RECORDING := 1
VBOX_WITH_AUDIO_RECORDING := 1
SDK_VBOX_VPX := 1
VBOX_WITH_LIBVPX := 1
SDK_VBOX_OPUS := 1
VBOX_WITH_LIBOPUS := 1
VBOX_BUILD_PUBLISHER := _OSE
В этом шаблоне необходимо кое-что подправить:
  • В переменных VBOX_CERTIFICATE_SUBJECT_NAME и VBOX_CERTIFICATE_SHA2_SUBJECT_NAME потребуется указать имена используемых вами сертификатов для подписи SHA-1 и SHA-256, соответственно.
  • В переменных VBOX_CERTIFICATE_FINGERPRINT и VBOX_CERTIFICATE_SHA2_FINGERPRINT пропишите цифровые отпечатки, которые были скопированы ранее из консоли управления сертификатами.
  • Если у вас не самоподписанный сертификат, а покупной, то удалите строчки с переменными VBOX_CROSS_CERTIFICATE_FILE_ARGS и VBOX_CROSS_CERTIFICATE_SHA2_FILE_ARGS, а в переменных VBOX_CROSS_CERTIFICATE_FILE и VBOX_CROSS_CERTIFICATE_SHA2_FILE (без «_ARGS») задайте полный путь к файлу кросс-сертификата (без него драйверы не будут считаться подписанными). Его можно найти на сайте компании, выпустившей сертификат, или у Microsoft.
  • Для более тонкой настройки подписывания имеется множество других переменных, с помощью которых можно задать хранилище, адрес сервера для наложения временно́й метки или вообще задать произвольный дополнительный набор аргументов для утилиты signtool. В файле Config.kmk под комментарием «Code Signing» можно посмотреть, какие там переменные определяются и как они используются.
  • Если вы устанавливали какие-то из программ в каталоги, отличающиеся от моих, нужно поправить пути в соответствующих переменных. Крайне желательно использовать тот же стиль слэшей (прямые/обратные), что приведён в шаблоне для каждой переменной: для некоторых из них это критично.
  • Для WiX необходимо указывать путь к исполняемым файлам. В портативной версии это каталог, куда был распакован архив; в установленной версии это подкаталог bin. Обратите внимание, что если путь содержит пробелы, то необходимо преобразовать его в формат 8.3. Для этого можно воспользоваться командой dir /x. Трюк со взятием в кавычки здесь, увы, не работает.
  • Переменная VBOX_BUILD_PUBLISHER задаёт брэндированный суффикс в номере версии. По умолчанию это «_OSE» (т. е. продукт имеет версию «6.0.4_OSE»). Здесь вы можете поменять его на что-то другое или даже на пустую строку, чтобы убрать суффикс совсем (если переменная отсутствует, применится суффикс «_OSE»).
Остальные переменные используются в основном для выбора собираемых компонентов. Ну и главная строка, ради которой всё и затевалось, идёт самой первой: отключаем hardening.

 Собираем VirtualBox


Ну вот, теперь, наконец, можно и приступать к сборке собственно VirtualBox. Если вы любите собирать под несколько архитектур параллельно, то придётся от этой привычки временно отказаться (или собирать в двух копиях дерева исходных кодов): здесь используется общий файл конфигурации, который нужно перегенерировать перед началом сборки. И если во время 64-битной компиляции в нём неожиданно окажутся пути к 32-битным библиотекам, компилятору это очень не понравится.
Для подписывания драйверов под Windows 10 нужно будет проделать дополнительные шаги, их описание приведено после основной процедуры.
  1. Начинаем со сборки 64-битной версии. Открываем консоль, выполняем команды:
    cd /d C:\Devel\VirtualBox-src
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 /win7
    COLOR 07
    set BUILD_TARGET_ARCH=amd64
    cscript configure.vbs --with-DDK=C:\WinDDK\7600.16385.1 --with-MinGW-w64=C:\Programs\mingw64 --with-MinGW32=C:\Programs\mingw32 --with-libSDL=C:\Programs\SDL\x64 --with-openssl=C:\Programs\OpenSSL\x64 --with-openssl32=C:\Programs\OpenSSL\x32 --with-libcurl=C:\Programs\curl\x64 --with-libcurl32=C:\Programs\curl\x32 --with-Qt5=C:\Programs\Qt\5.6.3-x64 --with-libvpx=C:\Programs\libvpx --with-libopus=C:\Programs\libopus --with-python=C:/Programs/Python
    env.bat
    kmk
    kmk C:/Devel/VirtualBox-src/out/win.x86/release/obj/Installer/VirtualBox-6.0.4_OSE-r128164-MultiArch_amd64.msi
    Скрипт configure.vbs проверяет окружение и создаёт файлы конфигурации (AutoConfig.kmk и env.bat). Первый запуск kmk выполняет сборку бинарных компонентов и помещает их в каталог out\win.amd64\bin\. Последняя команда собирает из этих компонентов промежуточный MSI-архив. Важные моменты:
    • Слэши в последней команде должны быть обязательно прямыми. С обратными kmk не найдёт сборочные правила.
    • Хоть мы собираем 64-битную версию, архив располагается в подкаталоге out\win.x86\…, потому что финальная сборка будет производиться из 32-битного окружения.
    • Если вы меняли суффикс версии, то «_OSE» в имени MSI-файла необходимо поправить на то, что вы задали в переменной VBOX_BUILD_PUBLISHER.
    • Ревизию в имени MSI-файла (128164) можно найти в файле Config.kmk в определении переменной VBOX_SVN_REV_FALLBACK. Имейте в виду, что это значение может отличаться от ревизии официальных дистрибутивов (например, версия 6.0.4 выпущена под номером 128413). Причины сего мне неизвестны, увы.
  2. Теперь компилируем 32-битную версию и пакуем весь комплект в единый инсталлятор. Открываем новую консоль, выполняем команды:
    cd /d C:\Devel\VirtualBox-src
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x86 /win7
    COLOR 07
    set BUILD_TARGET_ARCH=x86
    cscript configure.vbs --with-DDK=C:\WinDDK\7600.16385.1 --with-MinGW-w64=C:\Programs\mingw64 --with-MinGW32=C:\Programs\mingw32 --with-libSDL=C:\Programs\SDL\x32 --with-openssl=C:\Programs\OpenSSL\x32 --with-libcurl=C:\Programs\curl\x32 --with-Qt5=C:\Programs\Qt\5.6.3-x32 --with-libvpx=C:\Programs\libvpx --with-libopus=C:\Programs\libopus --with-python=C:/Programs/Python
    env.bat
    kmk
    kmk C:/Devel/VirtualBox-src/out/win.x86/release/bin/VirtualBox-6.0.4_OSE-r128164-MultiArch.exe
    Аналогично, суффикс «_OSE» в имени итогового файла надо поменять на свой.
    Обратите внимание, что в последней команде указано расширение EXE, а не MSI. Мы собираем сразу финальный инсталлятор, а промежуточный 32-битный MSI-архив соберётся автоматически, по зависимостям.
  3. Даже при наличии полноценного сертификата полученный таким образом дистрибутив не установится в Windows 10, если она загружена с включённым Secure Boot. Для этого драйверы должны быть подписаны непосредственно компанией Microsoft. Сама процедура описана на многих ресурсах и прямого отношения к теме моей статьи не имеет, поэтому здесь я только обозначу ключевые моменты и шаги, необходимые для интеграции процедуры в процесс сборки VB.
    • Необходимое условие: у вас должен иметься сертификат категории EV (Extended Validation), обычный здесь уже не подойдёт. Кроме того, вам нужно зарегистрироваться на портале Hardware Dev Center и привязать этот сертификат к аккаунту.
    • При сборке 64-битной версии после получения бинарных компонентов (первый запуск kmk, без параметров) необходимо создать CAB-архив с драйверами. Для этого в VB имеется шаблон скрипта, который сборочная система к этому моменту подредактировала в соответствии с текущей задачей и положила в подкаталог out\win.amd64\release\repack\. Нужно перейти туда и запустить следующую команду:
      PackDriversForSubmission.cmd -x
      По завершении работы скрипта в этом же каталоге появится файл с именем вида VBoxDrivers-6.0.4r128164-amd64.cab.
    • Полученный CAB-архив нужно подписать EV-сертификатом. Затем на портале Microsoft Hardware Dev Center создаётся новая заявка, загружается этот подписанный архив, выбирается желаемая целевая система (обязательно 64-битная), и заявка отправляется на выполнение.
    • Через несколько минут система должна выдать ZIP-архив, в котором драйверы в дополнение к имеющейся подписи имеют подпись Microsoft, а CAT-файлы сгенерированы заново. Этот архив скачивается и помещается куда-нибудь, где у сборочной системы будет к нему доступ.
    • Драйверы в этом архиве разложены по подкаталогам. Требуется все эти файлы извлечь, избавиться от всех этих подкаталогов и полученный набор скопировать в out\win.amd64\release\bin\, перезаписывая существующие файлы. Для этого удобно воспользоваться другим скриптом в том же каталоге out\win.amd64\release\repack\, его использование выглядит так:
      set _MY_SIGNTOOL=C:\Programs\DevKits\8.1\bin\x64\signtool.exe
      UnpackBlessedDrivers.cmd -n -i path\to\signed.zip
      Пути к signtool.exe и ZIP-архиву, разумеется, нужно подставить свои.
    • Теперь можно запускать вторую команду kmk, пакующую бинарные компоненты в MSI-инсталлятор. Если вы выполняли все действия в той же консоли, что и сборку, не забудьте вернуться в исходный каталог проекта.
    • Далее, как положено, приступаем к сборке 32-битной версии и проделываем в ней те же дополнительные шаги: после первого kmk переходим в out\win.x86\release\repack\, создаём CAB-архив, подписываем, отправляем в Microsoft (на этот раз выбрав 32-битную версию целевой системы), заменяем драйверы на переподписанные, после чего стартуем сборку финального дистрибутива.

Если ни я, ни вы ничего не перепутали, то после всех этих перипетий у вас должен получиться инсталлятор VirtualBox, отличающийся от Oracle-версии только значком исполняемого файла, картинкой в диалоге «О программе» и, конечно же, отключённым hardening'ом. При желании значок и картинку тоже можно поменять, но это тема отдельного разговора.

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

Добавлю ещё лишь пару слов об установке полученного дистрибутива с самоподписанным сертификатом. В современных системах (Windows 8/10) одного лишь включения тестового режима, как оказалось, недостаточно, при установке выводится сообщение о невалидной подписи. Чтобы обойти эту проблему, необходимо добавить использовавшиеся сертификаты в корневое хранилище:
  1. Откройте свойства скачанного файла дистрибутива: правый щелчок → Свойства, перейдите на вкладку Цифровые подписи. Там будут две подписи от «Roga and Kopyta Ltd»: sha1 и sha256. Выделяем первую, жмём Сведения.
  2. В открывшемся диалоге жмём кнопку Просмотр сертификата.
  3. В новом диалоге жмём Установить сертификат.
  4. Выбираем для установки «Локальный компьютер», нажимаем Далее. Подтверждаем UAC-запрос. Отмечаем пункт «Поместить все сертификаты в следующее хранилище», нажимаем Обзор и выбираем хранилище «Доверенные корневые центры сертификации». Далее, Готово. Сертификат установлен.
  5. Закрываем все диалоги, кроме самого первого, выделяем подпись sha256, повторяем для неё шаги 2–4.
  6. Закрываем все диалоги, запускаем установку. Теперь она должна пройти успешно.

 Послесловие


Размер статьи оказался неожиданностью для меня самого. Когда я начинал её писать, то намеревался подробно рассказывать, почему на каждом этапе было выбрано то или иное решение, какие конкретно ошибки выскакивают, если не применить очередную правку, и какие могут быть альтернативные подходы к решению этих ошибок. Но постепенно понял, что если бы я всё это описывал, статья получилась бы и вовсе неприподъёмной. Поэтому прошу прощения за встречающийся кое-где стиль «делай так, а почему — не скажу». Сам недолюбливаю такие инструкции, но тут не видел иного выхода. Впрочем, в отдельных местах я всё-таки постарался хотя бы вкратце пояснить суть происходящего.

Огромное количество аспектов сборочной системы VB осталось за кадром: как из-за нежелания раздувать текст, так и по причине моей лени, когда, найдя какой-то обходной путь для очередной проблемы, я не лез в глубины системы сборки, а поскорее переходил к следующему этапу. В конце концов, моей главной задачей было не найти оптимальный путь, а собрать, наконец, свой вариант актуального VirtualBox'а: сидеть на 4.3.12 уже поднадоело, но я не мог обновлять один из своих основных рабочих инструментов на нечто, что в любой момент может просто отказаться работать на неопределённый срок. Правда, по мере выхода новых версий я иногда узнаю о каких-нибудь новых возможностях сборочной системы и, опробовав их, добавляю соответствующую информацию в статью.

Надеюсь всё же, что, несмотря на недостатки, эта статья окажется кому-нибудь полезной. Для тех, кому лень поднимать всё вышеописанное нагромождение программ, но интересно расковырять получающийся в итоге дистрибутив, я выложил инсталлятор на Яндекс-диск: 6.0.4. Все драйверы в них (да и остальные файлы) подписаны недоверенным сертификатом, так что в 64-битной Windows этот вариант VB заработает только в тестовом режиме. Если имеются вопросы, пожелания, предложения — велкам в комментарии или в личку. И да пребудет с вами Open Source!

 Дополнения


Архив
• Публикация статьи, 21.01.2016
  1. VirtualBox 5.0.12.

• Обновление статьи от 24.05.2016
  1. Внесены уточнения с учётом изменений в VB 5.0.20, в частности, двойное подписывание SHA-1/SHA-256.
  2. Добавлено отключение флага принудительной проверки подписей, если собирается самоподписанный дистрибутив.
  3. Добавлена инструкция по обходу ошибки установки самоподписанного дистрибутива.
  4. Обновлены версии используемых библиотек.
  5. Для ускорения сборки отключены некоторые неиспользуемые компоненты.
  6. Исправлены мелкие недочёты.

• Обновление статьи от 29.07.2016
  1. Внесены уточнения с учётом изменений в VB 5.1.2, в частности, переход на Qt5. Отличия от процедуры сборки для 5.0.x оставлены в виде уточнений.
  2. Обновлены версии используемых библиотек.
  3. В итоговый сборочный скрипт добавлена проверка на корректность завершения каждой стадии.
  4. Исправлены мелкие недочёты.

• Обновление статьи от 15.09.2016
  1. Внесены уточнения с учётом изменений в VB 5.1.6.
  2. Обновлены версии используемых библиотек.
  3. Добавлено использование NASM для сборки OpenSSL.
  4. cURL теперь собирается с поддержкой OpenSSL, потому что иначе не работают функции проверки обновлений и загрузки пакета расширений.
  5. Доработан комбинированный скрипт сборки, чтобы версия определялась автоматически.
  6. Различные мелкие правки.

• Обновление статьи от 30.11.2016
  1. Внесены уточнения с учётом изменений в VB 5.1.10.
  2. Обновлены версии используемых библиотек, в частности, выполнен переход на OpenSSL 1.1.x.
  3. Исправлены ошибки инсталляции:
    • путь к плагинам Qt заменён на каталог установки приложения;
    • добавлены забытые библиотеки OpenSSL к 32-битным компонентам 64-битной версии VB.
  4. Удалена информация о сборке старых версий. Статья лежит в GitHub-проекте, поэтому всё сохранено в истории коммитов.

• Обновление статьи от 2.12.2016
  1. Использование статической версии OpenSSL.

• Обновление статьи от 20.06.2017
  1. Внесены уточнения с учётом изменений в VB 5.1.22.
  2. Актуализированы версии cURL, OpenSSL, gSOAP; поправлены сборочные инструкции для cURL, gSOAP и самого VB.

• Обновление статьи от 1.12.2017
  1. Внесены уточнения с учётом изменений в VB 5.2.2.
  2. Переход с MinGW-32 3.3.3 на 4.5.4.
  3. Актуализированы версии Qt, cURL, OpenSSL, gSOAP и некоторых сборочных инструментов; поправлены инструкции для cURL, gSOAP и самого VB.
  4. Использование локальных архивов DocBook XML/XSL вместо онлайн-версий.
  5. Переход с wget на cURL для скачивания образа гостевых дополнений.
  6. Различные мелкие правки.

• Обновление статьи от 4.12.2017
  1. Исправлена версия libxml в инструкциях.

• Обновление статьи от 4.09.2018
  1. Внесены уточнения с учётом изменений в VB 5.2.18.
  2. Актуализированы версии cURL, OpenSSL, gSOAP и некоторых сборочных инструментов; поправлены инструкции для cURL.

• Обновление статьи от 12.12.2018
  1. Внесены уточнения с учётом изменений в VB 5.2.22.
  2. Добавлена поддержка записи экрана, которая по умолчанию отключена в OSE-версии; используются библиотеки libopus и libvpx.
  3. Актуализированы версии cURL, OpenSSL, gSOAP.
  4. Добавлен единый патч-файл для внесения всех описанных изменений в дерево исходников VirtualBox.

• Обновление статьи от 25.01.2019
  1. Внесены уточнения с учётом изменений в VB 6.0.2.
  2. Улучшен механизм отключения сборки гостевых дополнений.
  3. Актуализированы версии cURL, gSOAP; откат DocBook XSL Stylesheets к версии 1.69.1 (точнее соответствующей структуре документации).
  4. Батник для сборки вынесен из текста статьи в загружаемый файл.

• Обновление статьи от 8.04.2019
  1. Статья переведена на английский язык; попутно внесено множество разнообразных правок в русскоязычную версию.
  2. Добавлена информация о подписывании драйверов для Windows 10.
  3. Внесены уточнения с учётом изменений в VB 6.0.4.
  4. Актуализированы версии cURL, OpenSSL, gSOAP и некоторые утилиты.
  5. Батник для сборки больше не привязан к конкретному пути проета, а также включает в себя базовый шаблон для автоматизации Win10-подписывания.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 31

    0
    Отличная работа, завтра проверю. Больше года назад слез с VB, который стал стабильно рушить рабочий десктоп в BSOD. По-гуглив проблему на форуме VB, понял, что никто не торопится исправить проблему. Хотя мне не актуально, но, так сказать, хочу тестером выступить.
      +1
      Читаю и думаю — кто же мог так обстоятельно и ясно всё расписать, да ещё и извиниться в конце за недостаточность? Ну, не удивлён, старая школа даёт себя знать.
        0
        И льстя моя будет страшна? :-)
        0
        К сожалению, не устанавливается.
        Скриншот ошибки
        image

          0
          Не сталкивался с таким. Посмотрите, пожалуйста, в журнале событий, какие там встречаются проблемы (Панель управления — Администрирование — Просмотр событий, группа «Журналы Windows», подкатегории «Система», «Приложение» и «Установка»).

          А, кстати, устанавливается ли официальный 5.0.14?
            0
            А, и ещё, попробуйте запустить инсталлятор с параметром --logging. Тогда во временном каталоге будет создан подкаталог VirtualBox с log-файлом, из которого, возможно, удастся вытащить какую-нибудь полезную информацию.
              0
              Эх, официальная устанавливается и до сих пор рушит систему в BSOD.
              Попытка запустить ключем к успеху не привела — каталог с логами не создается. В журналах есть сообщение об ошибке, но без подробностей.
                0
                Тогда, боюсь, это вне моей компетенции. :-(
                Собственно, улучшений у меня по сравнению с официальным пакетом ожидать в любом случае не приходилось, т. к. это просто пересборка, но почему установка может падать с такими странными симптомами — ни малейших идей нет.

                Если есть желание, можете попробовать промониторить через ProcMon, что вообще происходит, какие ошибки вылезают при обращении к разным файлам и веткам реестра. Может быть, это поможет определить, что конкретно не понравилось инсталлятору.
                0
                У меня такая же ошибка. Из лога:

                DIFXAPP: INFO: VBoxUSBMon.inf: checking signature with catalog 'C:\Program Files\Oracle\VirtualBox\drivers\USB\filter\VBoxUSBMon.cat'…
                DIFXAPP: ERROR: Signature verification failed while checking integrity of driver package 'VBoxUSBMon.inf' ('C:\Program Files\Oracle\VirtualBox\drivers\USB\filter\VBoxUSBMon.inf'). (Error code 0x800B0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.)
                DIFXAPP: INFO: Successfully removed '{B7D782D2-96DF-4775-A0E1-A76CF7B04B65}' from reference list of driver store entry ''
                DIFXAPP: INFO: RETURN: DriverPackageInstallW (0x800B0100)
                DIFXAPP: ERROR: encountered while installing driver package 'C:\Program Files\Oracle\VirtualBox\drivers\USB\filter\VBoxUSBMon.inf'
                DIFXAPP: ERROR: InstallDriverPackages failed with error 0x800B0100
                DIFXAPP: RETURN: InstallDriverPackages() 2148204800 (0x800B0100)
                CustomAction MsiInstallDrivers returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
                Action ended 13:53:39: InstallFinalize. Return value 3.


                Тестовый режим в Windows вклюен. Полный лог тут — pastebin.com/q2qFDUxH
                  0
                  Спасибо за лог.
                  Есть подозрение, что это связано с флагом обязательной проверки подписи, которую сборочные скрипты VB выставляют в бинарниках при наличии хоть какой-нибудь подписи (в частности, этот же флаг не даёт VB запускаться в 32-битной Windows из-за невалидной подписи, хотя той всегда было по барабану на сертификаты). Сейчас я пытаюсь определить, в каких случаях этот флаг необходим (MSDN говорит, что для драйверов он обязателен) и, соответственно, как надо подправить скрипты, чтобы он выставлялся, только когда реально нужен.

                  Пока что в качестве эксперимента я собрал неподписанный вариант. К сожалению, в 64-битке его невозможно установить в тестовом режиме, надо перезагружаться и в загрузочном меню выбирать Disable Driver Signature Enforcement.
              0
              Большое спасибо, обязательно попробую собрать.

              Кстати, если брать винду с торрентов, конфликт на удивление может быть вызван, например длл-кой отвечающей за набор иконок рабочего стола, и тому подобными мелочами.
              В некоторых случаях для запуска vbox, мне помог банальный sfc /scannow.

                0
                Да, есть и такие конфликты. Насколько я понимаю, это вызвано тем, что при модификации библиотек становится невалидной подпись, и харденинг блокирует загрузку таких системных библиотек, считая их зловредными.
                +2
                Статья обновлена с учётом версии 5.0.20. Также добавлена инструкция по обходу проблемы с неустанавливающимся самоподписанным дистрибутивом.
                  +1
                  Разобрался с переходом VB 5.1.x на Qt5, обновил статью.
                    0
                    Ещё одно обновление: исправлена проблема с нерабочими сетевыми функциями (проверка обновлений, скачивание extpack'а) из-за того, что cURL собирался без поддержки OpenSSL. Ну и ещё кой-чего по мелочи, см. апдейт в конце статьи.
                      0
                      Очередной апдейт для версии 5.1.10. Ключевое изменение — выполнен переход на OpenSSL 1.1.
                        0
                        А вот бы получить ссылку на закачку.
                          0
                          Ссылочка в конце поста.
                        0
                        Статья обновлена для VB 5.1.22. Также существенно поменялись процедуры сборки для последних версий некоторых библиотек.
                          +1
                          Огромное спасибо за столь подробную статью! Без нее мучался бы неделю, наверное, а так ушло всего часов 5 :)
                            0
                            Только сейчас заметил один нюанс. Инсталлятор, который скачивается с официального сайта, имеет внутри себя две версии — х86 и х64. Однако согласно данной инструкции, на выходе имеет два отдельных билда инсталлятора под разную разрядность. Возможно, подскажете, в какую сторону копнуть, чтобы они были одним целым? VBOX_WITH_COMBINED_PACKAGE, как я вижу, у Вас включен, но эффекта не дает.
                              0
                              Сорри за долгую реакцию, был без инета.
                              По данной инструкции получается именно комбинированный установщик, EXE-файл, внутри которого упакованы два MSI-пакета (32- и 64-битный) плюс CAB-архив с файлами, общими для обеих битностей.

                              Когда мы собираем 64-битную версию (VirtualBox-5.1.22_OSE-r115126-MultiArch_amd64.msi), это лишь промежуточный этап. На следующем шаге идёт не только сборка 32-битного пакета, но и упаковка всего собравшегося в единый инсталлятор. Я просто намеренно пропустил шаг сборки 32-битного MSI, потому что он автоматически собирается по зависимостям. После окончания сборки достаточно скопировать себе итоговый файл VirtualBox-5.1.22_OSE-r115126-MultiArch.exe, а всё остальное можно удалять. Оба MSI-пакета (ранее собранный 64-битный и свежесобранный 32-битный) уже находятся внутри.
                                0
                                Да, действительно, я не обратил внимание, что в последнем скрипте сборки путь к инсталлятору указывается другой. Вместо этого просто в скрипте для сборке х64 исправил архитектуру, в результате получал только два отдельных msi.

                                Кстати, обновил у себя исходники до 5.1.26, единственное что изменилось — теперь обязательно почему-то в параметрах к «cscript configure.vbs» нужно еще дописывать "--with-openssl32=C:\Programs\OpenSSL\x32". В остальном без изменений.

                                Спасибо!
                                  0
                                  нужно еще дописывать "--with-openssl32=C:\Programs\OpenSSL\x32"
                                  А это как раз поправили одну из штук, которую я до этого вынужден был вставлять ручками — переменные с суффиксом x86 в LocalConfig.kmk. Теперь конфигуратор сам их прописывает в соответствии с переданным путём. Там ещё 32-битный libcurl так же можно указывать, если не ошибаюсь.
                              +1
                              Очередное обновление, версия 5.2.2.

                              Ключевое изменение: теперь для 32-битных VBoxRem (VirtualBox Recompiler) используется MinGW 4.5.4, а не 3.3.3. Это, теоретически, может вызвать проблемы при работе на 32-битных хостах (в первую очередь, с выключенной виртуализацией). Я немного потестировал в таком режиме, проблем не обнаружил, поэтому счёл возможным перейти на такую сборку как на основную.
                                0
                                Апдейт до версии 5.2.18 с попутным обновлением библиотек и всякой мелочёвки.
                                  +2
                                  Я тут обнаружил, что в собранной мной версии не работает запись с экрана виртуальных машин: крутилятор в строке состояния крутится, а видеофайл не создаётся. Оказалось, что для OpenSource-версии эта функция явным образом отключена. Причин я так и не уяснил, но как включить обратно, разобрался. Статья обновлена с учётом этой информации, ну и, как обычно, актуализированы версии VB и библиотек.
                                    0
                                    Разобрался со сборкой новой линейки версий, инструкция обновлена до версии 6.0.2.
                                      0

                                      CaptainFlint, Могли бы вы проверить почту, указанную в контактах на вашем сайте? У нас есть предложение о сотрудничестве

                                        0
                                        Почта у меня support_at_flint-inc_dot_ru. А то была не почта, а джаббер-аккаунт, почтой на нём я не пользуюсь (о чём должен был прийти автоответ). Залез туда, прочёл письмо — учитывая обновление статьи, думаю, что предложение уже неактуально. :-)
                                        +1
                                        Очередное обновление статьи. Основное добавление — информация о подписывании драйверов для Windows 10 (к сожалению, доступное немногим). Ну и попутная актуализация версий VB и разных библиотек.

                                        Only users with full accounts can post comments. Log in, please.