Обход некоторых ограничений утилиты BUILD
Oct 28, 2010 · CommentsBUILDWDK
Система сборки в Windows Driver Kit базируется на утилите BUILD. Эта утилита сканирует структуру проектов, отслеживает зависимости (к сожалению далеко не все) и подготавливает окружение для запуска NMAKE, который, собственно, и выполняет всю черновую работу по сборке. К сожалению, BUILD создавался и развивался по принципу «так получилось», исключительно эволюционным путем – как средство сборки исходников Windows. Так что эта утилита некоторыми неудобными ограничениями.
Одно из них – полное непонимание переменных и директив препроцессора.
К примеру, нужно исключить определённую директорию из дерева сборки если объявлен макрос NOBUILD. Пишем вот такой DIRS файл:
!if defined(NOBUILD)
DIRS = \
foo \
!else
DIRS = \
foo \
bar \
!endif
Вне зависимости от того, объявлен макрос NOBUILD или нет, BUILD попытается собрать обе директории foo и bar. Более того, вот такой DIRS файл тоже не вызовет ошибку:
Some random garbage in DIRS file.
DIRS = \
foo \
bar \
More random garbage.
Почему? Потому, что BUILD просто сканирует файл в поиске текста, похожего на объявление директив DIRS и OPTIONAL_DIRS игнорируя остальной текст. Впрочем, макроподстановки разворачиваются правильно:
FOO = \
foo \
DIRS = \
$(FOO) \
bar \
Аналогичная ситуация с файлом SOURCES. BUILD игнорирует директивы препроцессора, интересуясь только объявлением макроса SOURCES и его платформо-зависимых вариантов. Полностью, все эти директивы обрабатываются только утилитой NMAKE. Как же быть?
Каждая директория, предназначенная для сборки, содержит файл MAKEFILE:
#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the components of NT OS/2
#
!INCLUDE $(NTMAKEENV)\makefile.def
Именно этот файл читается NMAKE, для каждого из трех проходов (PASS0, PASS1 и PASS2). По умолчанию, он просто включает стандартные правила сборки, работающие с SOURCES. (Начиная с WDK для Vista MAKEFILE стал опциональным. В случае его отсутствия, автоматически используется MAKEFILE.DEF.) Примерное дерево включений make-файлов выглядит вот так:
MAKEFILE
+- MAKEFILE.DEF
+- MAKEFILE.NEW
+- MAKEFILE.PLT
+- PROJECT.MK
+- SOURCES
+- _OBJECTS.MAC
+- $(TARGET_DIRECTORY)mk.inc
+- MAKEFILE.INC
+- …
Откуда видно, что MAKEFILE и MAKEFILE.INC – крайне полезны для нетривиальных манипуляций с логикой сборки. Так, чтобы решить оригинальную задачу, достаточно не включать MAKEFILE.DEF в случае, если объявлен макрос NOBUILD:
!if !defined(NOBUILD)
#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the components of Windows NT
#
!INCLUDE $(NTMAKEENV)\makefile.def
!endif
В результате, BUILD по-прежнему вызовет NMAKE, но тот проигнорирует данную директорию.