GNU make -j вариант

С тех пор, как я узнал о -j, я использовал -j8 blithely. На днях я составлял установку атласа, и make не удалось. В конце концов я отследил его до того, что делались не по порядку - и он работал нормально, как только я вернулся к singlethreaded make. Это заставляет меня нервничать. Какие условия мне нужно отслеживать при написании собственных файлов make, чтобы не делать что-то неожиданное с make -j?

Ответ 1

Я думаю, make -j будет уважать зависимости, которые вы указываете в своем Makefile; то есть если вы укажете, что objA зависит от objB и objC, тогда make не начнет работать с objA до тех пор, пока objB и objC не будут завершены.

Скорее всего, ваш Makefile не достаточно точно определяет необходимый порядок операций, и просто удача в том, что это работает для вас в однопоточном случае.

Ответ 2

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

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

Эта ссылка является хорошим пособием по некоторым проблемам с параллельным make.

Ответ 3

Вот пример проблемы, с которой я столкнулся, когда начал использовать параллельные сборки. У меня есть цель, называемая "свежей", которую я использую для восстановления цели с нуля ( "новая" сборка). Раньше я кодировал "свежую" цель, просто указывая "clean", а затем "build" в качестве зависимостей.

build: ## builds the default target
clean: ## removes generated files
fresh: clean build ## works for -j1 but fails for -j2

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

fresh:
    $(MAKE) clean
    $(MAKE) build

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

Ответ 4

Если у вас есть рекурсивный make, все может легко сломаться. Если вы не делаете рекурсивный make, то, пока ваши зависимости корректны и полны, вы не должны сталкиваться с какими-либо проблемами (за исключением ошибки в make). См. Рекурсивный анализ считается вредным для более подробного описания проблем с рекурсивным make.

Ответ 5

Хорошей идеей является автоматизированный тест для тестирования опции -j для всех файлов make. Даже у лучших разработчиков есть проблемы с опцией -j make. Наиболее распространенными проблемами являются самые простые.

myrule: subrule1 subrule2
     echo done

subrule1:
     echo hello

subrule2:
     echo world

В обычном make вы увидите hello → world → done. С make -j 4 вы можете увидеть мир → привет → сделано

Где я вижу, это происходит чаще всего с созданием выходных каталогов. Например:

build: $(DIRS) $(OBJECTS)
     echo done

$(DIRS):
     [email protected] -p [email protected]

$(OBJECTS):
     $(CC) ...

Ответ 6

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

Затем выполнение make показывает различия с:

  • сделать
  • make -j4

all: toprule1

toprule1: botrule2 subrule1 subrule2
    @echo toprule 1 start
    @sleep 0.01
    @echo toprule 1 done

subrule1: botrule1
    @echo subrule 1 start
    @sleep 0.08
    @echo subrule 1 done

subrule2: botrule1
    @echo subrule 2 start
    @sleep 0.05
    @echo subrule 2 done

botrule1:
    @echo botrule 1 start
    @sleep 0.20
    @echo "botrule 1 done (good prerequiste in sub)"

botrule2:
    @echo "botrule 2 start"
    @sleep 0.30
    @echo "botrule 2 done (bad prerequiste in top)"