Измените старую систему make-файлов, чтобы использовать преимущества параллельных компиляций - PullRequest
0 голосов
/ 01 февраля 2011

Мы используем Microsoft NMAKE для компиляции большого количества собственных C ++ и некоторых файлов Intel Fortran.Обычно make-файлы содержат такие строки (для каждого файла):

$ (LINKPATH) \ olemisc.obj: ole2 \ olemisc.cpp $ (OLEMISC_DEP)
$ (CCDEBUG) ole2 \ olemisc.cpp
$ (GDEPS) ole2 \ olemisc.cpp

OLEMISC_DEP = \
e: \ ole2 \ ifaceole.hpp \
e: \ ole2 \ cpptypes.hpp \
и т. Д.

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

One: GNU make позволяет вам выполнять параллельные задания, например, с опцией --jobs = 2, и это прекрасно работает с GCC (мы не можем использовать GCCк сожалению).Но NMAKE от Microsoft, похоже, не поддерживает такую ​​возможность.Насколько совместимы эти две программы имен, и если бы мы начали использовать GNU MAKE, могли бы вы запустить два процесса cl.exe одновременно?Я ожидаю, что они будут жаловаться на блокировку файла PDB (отладки), или один из новых аргументов командной строки cl.exe поможет вам с этим?

Two: cl.exeимеет флаг / MP (сборка с несколькими процессами), который позволяет компилировать несколько файлов одновременно, если они передаются вместе через командную строку, например:

cl / MP7 a.cpp b.cpp c.cpp d.cpp e.cpp

Но использование этого потребует внесения изменений в make-файл.Наши make-файлы генерируются нашей собственной программой из других файлов, поэтому я могу легко изменить то, что мы помещаем в make-файлы.Но как объединить зависимости из разных файлов cpp вместе в make-файле, чтобы они были скомпилированы вместе с помощью одного вызова cl.exe?Каждый .obj - это отдельная цель с набором команд для ее создания?

Или я могу изменить make-файл так, чтобы он не вызывал cl.exe, а скорее какой-то другой маленький исполняемый файл, который мы пишем, который затем собирает последовательностьфайлов .cpp вместе и оболочки в cl.exe, передавая несколько аргументов?Это будет работать и кажется выполнимым, но также кажется слишком сложным, и я не вижу, чтобы кто-то еще делал это.

Я что-то упускаю из виду?Должен быть более простой способ сделать это?

Мы не используем Visual Studio или файл решения для компиляции, потому что список файлов обширный, у нас есть несколько специальных элементов в наших make-файлах, итеоретически не хочу быть чрезмерно привязанным к MS C ++ и т. д.

Ответы [ 3 ]

1 голос
/ 18 марта 2011

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

По сути, система make знает, что ей нужночтобы создать определенный файл obj, и как только он найдет правило вывода, которое позволяет ему это сделать, он будет его использовать.

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

1 голос
/ 01 февраля 2011

Я настоятельно рекомендую GNU make для Windows.Я склонен использовать cygwin make, поскольку среда, которую он создает, имеет тенденцию быть очень переносимой на Unix-подобные платформы (Mac и Linux для начала).Компиляция с использованием набора инструментов Microsoft, параллельно и со 100% точными зависимостями и использованием процессора работает очень хорошо.У вас есть и другие требования.

Что касается вашего nmake вопроса, найдите в руководстве правила вывода в пакетном режиме .По сути, nmake может вызвать компилятор C один раз, передав ему всю загрузку файлов C за один раз.Таким образом, вы можете использовать переключатели типа /MP... компилятора.

Параллельная компиляция, встроенная в компилятор?Тьфу!Ужасно сломлен я говорю.В любом случае вот скелет:

OBJECTS = a.obj b.obj c.obj
f.exe: $(OBJECTS)
    link $** -o $@

$(OBJECTS): $$(@R).c

# "The only syntactical difference from the standard inference rule
# is that the batch-mode inference rule is terminated with a double colon (::)."
.c.obj::
    cl -c /MP4 $<

РЕДАКТИРОВАТЬ

Если каждый .obj имеет свои зависимости (вероятно!), То вы просто добавляете их как отдельные зависимостилинии (т. е. к ним не прикреплены какие-либо команды оболочки).

a.obj: b.h c.h ../include/e.hpp
b.obj: b.h ../include/e.hpp
    ∶

Часто такая табличка генерируется другим инструментом и !INCLUDE d в основной сборочный файл.Если вы умны, вы можете генерировать эти зависимости бесплатно во время компиляции.(Если вы зайдете так далеко, то nmake начнет скрипеть по швам, и вам, возможно, следует перейти на GNU make.)

0 голосов
/ 17 марта 2011

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

В старом стиле, который компилирует один файл за раз, есть тонны этого:

$(LINKPATH)\PS_zlib.obj : zlib\PS_zlib.cpp $(PS_ZLIB_DEP)
        $(CC) zlib\PS_zlib.cpp

$(LINKPATH)\ioapi.obj : zlib\minizip\ioapi.c $(IOAPI_DEP)
        $(CC) zlib\minizip\ioapi.c

$(LINKPATH)\iowin32.obj : zlib\minizip\iowin32.c $(IOWIN32_DEP)
        $(CC) zlib\minizip\iowin32.c

Обратите внимание, что каждый файл компилируется по одному. Поэтому теперь вы хотите использовать причудливый ключ Visual Studio 2010 / MP "/ MP [n] использовать до 'n' процессов для компиляции", чтобы компилировать несколько файлов одновременно. Как? Ваш make-файл должен использовать правила пакетного вывода в nmake следующим образом:

$(LINKPATH)\PS_zlib.obj : zlib\PS_zlib.cpp $(PS_ZLIB_DEP)

$(LINKPATH)\ioapi.obj : zlib\minizip\ioapi.c $(IOAPI_DEP)

$(LINKPATH)\iowin32.obj : zlib\minizip\iowin32.c $(IOWIN32_DEP)

#Batch inference rule for extension "cpp" and path "zlib":
{zlib}.cpp{$(LINKPATH)}.obj::
        $(CC) $(CCMP) $<

#Batch inference rule for extension "c" and path "zlib\minizip":
{zlib\minizip}.c{$(LINKPATH)}.obj::
        $(CC) $(CCMP) $<

В этом случае в другом месте мы имеем

CCMP = /MP4

Обратите внимание, что правила пакетного вывода nmake не поддерживают подстановочные знаки или пробелы в путях. Я нашел где-то приличную документацию nmake, в которой говорится, что вам нужно создать отдельное правило для каждого расширения и местоположения исходного файла, вы не можете иметь одно правило, если файлы находятся в разных местах. Кроме того, файлы, которые используют #import, не могут быть скомпилированы с /MP.

У нас есть инструмент, который генерирует наши make-файлы, поэтому теперь он также генерирует правила пакетного вывода.

Но это работает! Время для компиляции одной большой библиотеки DLL уменьшилось с 12 до 7 минут! Woohoo!

...