Вы можете попробовать что-то вроде:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
И назовите это с:
$ make -j20 -l30 concurrent-linkers=2
По сути, он разделяет сборку на два вызова make, один для компиляции и один для ссылки, с различными параметрами -j
. Основным недостатком является то, что все компиляции должны быть закончены до начала первой ссылки. Лучшим решением было бы спроектировать простой сервер заданий на связывание (простой сценарий оболочки с небольшим количеством flock
и файлами тегов сделал бы его) и делегировать ему задания на связывание. Но если вы можете жить с этим ...
Демо с фиктивным Makefile:
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...\n' && sleep 2 && printf 'done\n' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
Как видите, все $(OBJS)
цели строятся параллельно, в то время как $(EXES)
цели строятся 2 (максимум) за раз.
РЕДАКТИРОВАТЬ Если ваш make-файл сгенерирован CMake, есть как минимум две опции:
Настройте ваши файлы CMake так, чтобы CMake генерировал два разных make-файла: один для компиляции и один для ссылки. Затем напишите простой make-файл обертки, например:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilation
Убедите CMake (если это еще не так) сгенерировать make-файл, который определяет две переменные make: одну (OBJS
), равную списку всех объектных файлов, и одну (EXES
), равную список всех исполняемых файлов. Затем напишите простой make-файл обертки, например:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
Очень похожее решение существует, если вместо этого CMake генерирует две фальшивые цели, одну для всех объектных файлов и другую для всех исполняемых файлов:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: cmake-target-for-compilation
$(MAKE) -j $(concurrent-linkers) cmake-target-for-link