Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Make
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
demiurg_spb
Сегодня попробовал задать мейку во сколько потоков ему работать, т.к. у меня в системе видятся 4 ядра (1+HT)*2 то я задал 4:
Код
make -j 4 all

Результат: проект собрался ровно в 2 раза быстрее!

Спешу поделиться своей радостью со всеми:-)
klen
Разделяем Вашу радость sm.gif
если задать число более чем число возможных потоков то еще быстрее будет по причине того что поточи часто блокируются подсистемой ввода вывода, и в это время отпускают процессорв. на малом числе не заметно, а вот если проект сложный то эффект без очков заметен.

demiurg_spb
Спасибо за наводку!
Проверил, у меня видимо не такой большой проект...
При дальнейшем увеличении потов скорость сборки не изменяется, как была 18 секунд, так и остаётся.

А можно-ли как-то из самого мейк-файла передавать мейк-утилите эту же информацию что и аргумент j?
IgorKossak
Попробовал подобным образом сделать ребилд, т. е.
Код
make -j 2 clean all

Получил следующую хохму - в одном потоке делалась компиляция, а в другом благополучно всё чистилось. Таким образом, когда дело дошло до линкера, то вылезла масса ошибок из-за нехватки объектных файлов. biggrin.gif
_Pasha
Цитата(IgorKossak @ Aug 22 2012, 09:42) *

Всё. Последний аргумент перехода на scons.
там это всё вручную планируется, с нужным результатом sm.gif
ReAl
Цитата(demiurg_spb @ Aug 21 2012, 22:39) *
А можно-ли как-то из самого мейк-файла передавать мейк-утилите эту же информацию что и аргумент j?
Из окружения (и на каждом компе своё), в переменной MAKEFLAGS
(через эту же переменную передаются флаги «вложенным» вызовам $(MAKE) )


Цитата(IgorKossak @ Aug 22 2012, 09:42) *
Получил следующую хохму - в одном потоке делалась компиляция, а в другом благополучно всё чистилось. Таким образом, когда дело дошло до линкера, то вылезла масса ошибок из-за нехватки объектных файлов. biggrin.gif
Так если в файловом менеджере запустить копирование какого-то каталога и тут же чразу его удаление, так тоже весело будет.

Если на -j рассчитывать, то надо бы цель отдельную
Код
rebuild:
    $(MAKE) clean
    $(MAKE)
AHTOXA
Цитата(ReAl @ Aug 22 2012, 18:25) *
Если на -j рассчитывать, то надо бы цель отдельную
Код
rebuild:
    $(MAKE) clean
    $(MAKE)

У меня была именно такая цель:
Код
build: clean all

И всё равно с -j получилась ерунда - при первом вызове ничего не произошло (как будто всё up-to date), и лишь при втором начало-таки компилироваться.
Но, что меня удивило больше - скорость компиляции визуально не изменилась. Поэтому я убрал -j, отложив многопоточную сборку до освоения scons (то есть до следующей жизни sm.gif ).
DmitryM
eCos по умолчанию собирается -j 4
demiurg_spb
Цитата(ReAl @ Aug 22 2012, 16:25) *
Из окружения (и на каждом компе своё), в переменной MAKEFLAGS...
То что надо, спасибо!

У меня для сборки всех конфигураций понаписаны батники типа этого (в таком варианте гонки целей исключены, но хотелось бы более элегантное решение найти):
Код
set MAKEFLAGS=-j 4
for /L %%i in (0#,1#,36#) do (
    call make.exe clean    --quiet COMPILE_TYPE=%%i
    if ERRORLEVEL 1 goto ERROR     
    call make.exe all      --quiet COMPILE_TYPE=%%i
    if ERRORLEVEL 1 goto ERROR     
    call make.exe clean    --quiet COMPILE_TYPE=%%i
    if ERRORLEVEL 1 goto ERROR     
    call make.exe boot_all --quiet COMPILE_TYPE=%%i
    if ERRORLEVEL 1 goto ERROR     
)
goto EOF
:ERROR
echo  Compilation error!
pause
exit
:EOF
Эффект от многопоточной сборки значительный: вместо 13 минут всё за 7 минут пересобирается.
И чем больше исходников в проекте тем эффект более выражен.
Цитата(AHTOXA @ Aug 22 2012, 19:44) *
Но, что меня удивило больше - скорость компиляции визуально не изменилась.
А что за процессор в компьютере?
AHTOXA
Цитата(demiurg_spb @ Aug 23 2012, 02:14) *
А что за процессор в компьютере?

Pentium dual-core 2GHz.
Сейчас замерил с секундомером, разница-таки есть: 35 сек против 40. А с -j 2 - 30 сек.
ReAl
Цитата(AHTOXA @ Aug 22 2012, 18:44) *
У меня была именно такая цель:
Код
build: clean all

И всё равно с -j получилась ерунда - при первом вызове ничего не произошло (как будто всё up-to date), и лишь при втором начало-таки компилироваться.
Конечно, цель-то таки ж не такая.
Тут build зависит от двух других, которые могут и в разном порядке достигаться. Если сначала достигнется all (проверили — всё на месте) и только потом clean (пока то проверялось — составляли список чего тереть), то такой эфект и будет.

Я привёл цель без зависимостей с двумя последовательными действиями, каждое из которых может распараллеливаться, но между ними «точка следования» :-)

Сейчас на ноуте с i3 (два ядра по два потока) типовая команда make -j 4 program, ещё ни разу непоняток из-за кривого порядка не было.
AHTOXA
Да, наверняка всё так и есть. Но мне это не нравится.
Часто вижу варианты типа:
Код
all: message_begin elf size message_end

Получается, что все эти варианты тоже будут глючить от многопоточности. Имхо, надо было и в такой перечень целей вставить «точки следования».
IgorKossak
AHTOXA
+1
Любую переделку мейкфайлов считаю моветоном.
Petka
Цитата(AHTOXA @ Aug 23 2012, 11:53) *
Да, наверняка всё так и есть. Но мне это не нравится.
Часто вижу варианты типа:
Код
all: message_begin elf size message_end

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

Банальная безграмотность создателей таких make файлов.
AHTOXA
Цитата(Petka @ Aug 23 2012, 14:52) *
Банальная безграмотность создателей таких make файлов.

Ой ли? Сдаётся мне, что ключ -j появился далеко не сразу. И к этому времени было уже очень много таких вот "безграмотных" мейкфайлов.
Petka
Цитата(AHTOXA @ Aug 23 2012, 14:28) *
Ой ли? Сдаётся мне, что ключ -j появился далеко не сразу. И к этому времени было уже очень много таких вот "безграмотных" мейкфайлов.

Это не причина НЕ исправлять такие makefile.
Раньше и в компиляторах не было volatile. Но это не причина НЕ исправлять старый код.
ReAl
Цитата(AHTOXA @ Aug 23 2012, 10:53) *
Код
all: message_begin elf size message_end

Получается, что все эти варианты тоже будут глючить от многопоточности. Имхо, надо было и в такой перечень целей вставить «точки следования».
size сам зависит от elf, так что там без проблем, message_begin иногда выскакивает после compiling от первого %.o. Это немного неприятно, не не смертельно. Там и предупреждения/ошибки компилятора идут вперемешку с compiling по мере появления, всё равно смотреть потом внимательно надо :-)
И править это руки не доходят. А важные вещи, в отличие от декора, вроде как нормально (ну кроме make clean all).

По правке — полностью согласен в мнением по volatile :-)
Более того, volatile уже давно как был, но с ростом пронырливости компилятора приходится править то, где эти volatile есть, но в других местах (например, так было с чтением системного тика в scmRTOS).
AHTOXA
Цитата(Petka @ Aug 23 2012, 18:55) *
Это не причина НЕ исправлять такие makefile.
Раньше и в компиляторах не было volatile. Но это не причина НЕ исправлять старый код.

Хорошо хоть, что с этих мейкфайлов снято обвинение в «безграмотности», теперь они просто «старый код» sm.gif
А теперь представьте, что в следующей версии make введут новый ключик, и вам придётся править все свои мейкфайлы. Имхо, это неправильно. И сравнение с volatile здесь не совсем уместно - в случае make ничто не мешало авторам поставить между субцелями пресловутые «точки следования».
ReAl
Цитата(AHTOXA @ Aug 23 2012, 20:33) *
А теперь представьте, что в следующей версии make введут новый ключик, и вам придётся править все свои мейкфайлы. Имхо, это неправильно.
Неправильно будет, если ключик по умолчанию будет включен.
А так: не хош -- не пользуй, хош -- подстройся. Всё честно.

Цитата(AHTOXA @ Aug 23 2012, 20:33) *
случае make ничто не мешало авторам поставить между субцелями пресловутые «точки следования».
«Ага, щас»™
В результате для
Код
%.elf : $(OBJS)

между файлкми из $(OBJS) будет по точке следования и -j N идёт лесом. Параллельно их создавать будет нельзя.
Спасибо, не надо.
Я лучше пешком постою ручками всё поправлю там, где я не рассчитал на -j
Petka
Цитата(AHTOXA @ Aug 23 2012, 21:33) *
Хорошо хоть, что с этих мейкфайлов снято обвинение в «безграмотности», теперь они просто «старый код» sm.gif
А теперь представьте, что в следующей версии make введут новый ключик, и вам придётся править все свои мейкфайлы. Имхо, это неправильно. И сравнение с volatile здесь не совсем уместно - в случае make ничто не мешало авторам поставить между субцелями пресловутые «точки следования».

ИМХО вывод сообщений неправильно организовывать как подцели какой-либо цели.
По замыслу make, подцели необязательно вообще будут выполняться by design.
Про определённый порядок выполнения зависимостей нигде никогда ничего не гарантировалось.
Всё что вы просили выполнить в вашем makefile для цели all будет добросовестно выполнено. Вывод на экран сообщений был? Размер выводился? elf собирался? При любом ключе -j ?
Проводя аналогии с компиляторами: сейчас уже никого не удивляет, что в ассемблерном листинге оптимизирующего компилятора фактический порядок "промежуточных" арифметических вычислений может отличатся от написанного в исходном тексте программы. Не говоря уже о выкидывании незадействованного кода. Если программист заложился на какие-то побочные свойства инструмента - это только ответственность программиста а не проблема инструмента.
AHTOXA
Цитата(Petka @ Aug 24 2012, 01:39) *
Про определённый порядок выполнения зависимостей нигде никогда ничего не гарантировалось.

Пока не появился ключик -j - вполне себе гарантировалосьsm.gif
Цитата(Petka @ Aug 24 2012, 01:39) *
Всё что вы просили выполнить в вашем makefile для цели all будет добросовестно выполнено. Вывод на экран сообщений был? Размер выводился? elf собирался? При любом ключе -j ?

Нет. В моём примере (build: clean all) - как раз-таки ничего не собиралось. Ибо сначала выполнялась цель all, а потом - clean. В результате после выполнения make build - никакого elf-а не было.
Цитата(ReAl @ Aug 24 2012, 01:28) *
«Ага, щас»™
В результате для
Код
%.elf : $(OBJS)

между файлкми из $(OBJS) будет по точке следования и -j N идёт лесом. Параллельно их создавать будет нельзя.

Так я про PHONY цели. Между ними (после них) вполне можно было поставить точки следования.
alx2
Цитата(AHTOXA @ Aug 22 2012, 20:44) *
У меня была именно такая цель:
Код
build: clean all

Это не одно и то же.
Вы указали две разные цели (clean и all). Каждая из этих целей имеет свой рецепт, и при указании -j эти два рецепта выполняются параллельно.
В примере же ReAl один рецепт из двух строк. Эти строки всегда будут выполняться последовательно независимо от наличия или отсутствия -j.
Petka
Цитата(AHTOXA @ Aug 24 2012, 00:40) *
Пока не появился ключик -j - вполне себе гарантировалосьsm.gif

После этого утверждения была бы уместна ссылка на документацию какой-то определённой версии make. С подтверждением этого смелого утверждения.
Цитата
Нет. В моём примере (build: clean all) - как раз-таки ничего не собиралось. Ибо сначала выполнялась цель all, а потом - clean. В результате после выполнения make build - никакого elf-а не было.
...

В этом примере для цели build необходимо удовлетворение двух взаимоисключающих подцелей. Вы так построили сценарий для make. При чём тут инструмент?
Мне вся эта ситуация напоминает появление процессоров с "Hyper-threading". Тогда программисты не были готовы к настоящему параллельному выполнению потоков и отсутствие всяких "spin_lock" приводило к непредсказуемым результатам.
AHTOXA
Цитата(Petka @ Aug 24 2012, 13:05) *
После этого утверждения была бы уместна ссылка на документацию какой-то определённой версии make. С подтверждением этого смелого утверждения.

Это совершенно очевидно. Один поток - цели выполняются последовательно.
Цитата(Petka @ Aug 24 2012, 13:05) *
В этом примере для цели build необходимо удовлетворение двух взаимоисключающих подцелей. Вы так построили сценарий для make. При чём тут инструмент?

Не взаимоисключающих, а последовательных. Без -j всё работает как задумано. Если бы при добавлении ключика -j ввели точки следования после каждой из PHONY-целей, то всё бы работало и с -j. Я считаю это большой глупостью авторов make.
Короче, вы меня не переубедите. Инструмент этот (make) - кривой. Уж сколько времени я им пользуюсь, а ощущение кривизны не проходит, а только усиливается.
Petka
Цитата(AHTOXA @ Aug 24 2012, 12:03) *
Это совершенно очевидно. Один поток - цели выполняются последовательно.

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

Именно взаимоисключающих. Про последовательность см. выше. Так же прошу ссылку на документацию, где оговорен порядок выполнения целей.
Цитата
....
Короче, вы меня не переубедите. Инструмент этот (make) - кривой. Уж сколько времени я им пользуюсь, а ощущение кривизны не проходит, а только усиливается.

Жаль.

Тут сделал пару тестов:
Код
all: first second third

first:
    sleep 3
    echo first

second:
    sleep 2
    echo second

third:
    sleep 1
    echo third

.PHONY: first second third


Код
$ make


Код
sleep 3
echo first
first
sleep 2
echo second
second
sleep 1
echo third
third


Код
make -j 3


Код
sleep 3
sleep 2
sleep 1
echo third
third
echo second
second
echo first
first


Если нам важен порядок немного патчим кривой makefile без создания промежуточных целей:
Код
all: first second third

first:
    sleep 3
    echo first

second: | first
    sleep 2
    echo second

third: | second
    sleep 1
    echo third

.PHONY: first second third


Код
make -j 3


Код
sleep 3
echo first
first
sleep 2
echo second
second
sleep 1
echo third
third


Вуаля!
Может кому-нибудь будет полезно.
alx2
Цитата(AHTOXA @ Aug 24 2012, 13:03) *
Это совершенно очевидно. Один поток - цели выполняются последовательно.
Вы говорите о разном. sm.gif
Совершенно бесспорно, что без -j выполнение происходит последовательно. Petka же говорил(а) о порядке обработки целей в этой последовательности. То, что рецепты выполняются последовательно, а не параллельно, под сомнение не ставилось...

Цитата(AHTOXA @ Aug 24 2012, 13:03) *
Не взаимоисключающих, а последовательных. Без -j всё работает как задумано. Если бы при добавлении ключика -j ввели точки следования после каждой из PHONY-целей, то всё бы работало и с -j.

sm.gif Если после каждой цели (каждого рецепта) ввести точку последовательности, то и сборка будет выполняться строго последовательно. Таким образом, весь эффект опции -j (которая как раз предписывает выполнять рецепты параллельно) будет уничтожен. В таком случае, просто не указывайте -j, и Вы получите желаемое!

Возможно, я просто не понял, что Вы имели в виду, говоря о точках последовательности (я понимаю "точка последовательности" как то, что новый рецепт начинает выполняться только после завершения выполнения предыдущего), в таком случае, буду благодарен за разъяснение (еще лучше с примером).
AHTOXA
Цитата(alx2 @ Aug 27 2012, 11:32) *
Вы говорите о разном. sm.gif
Совершенно бесспорно, что без -j выполнение происходит последовательно. Petka же говорил(а) о порядке обработки целей в этой последовательности.

Ну мы вроде как друг-друга понялиsm.gif По факту порядок обработки целей совпадает с порядком их объявления. Хотя я и не встречал в документации явных гарантий этого.
Цитата(alx2 @ Aug 27 2012, 11:32) *
sm.gif Если после каждой цели (каждого рецепта) ввести точку последовательности, то и сборка будет выполняться строго последовательно. Таким образом, весь эффект опции -j (которая как раз предписывает выполнять рецепты параллельно) будет уничтожен.
Я написал не "каждой цели", а "каждой PHONY-цели". Так что эффект останется.
Цитата(alx2 @ Aug 27 2012, 11:32) *
В таком случае, просто не указывайте -j, и Вы получите желаемое!

Так и делаю, не переписывать же многие десятки makefile-ов.
(И, вдохновлённый этим обсуждением, снова почитываю про scons... sm.gif )
e-serg
Цитата(AHTOXA @ Aug 24 2012, 04:40) *
Пока не появился ключик -j - вполне себе гарантировалосьsm.gif

Ключик -j очень старый, лет 10 назад он уже был старым.

PS. 1989г, make, ключ -j уже имеется.
AHTOXA
И? Это вы к чему?
e-serg
Цитата(AHTOXA @ Aug 28 2012, 13:28) *
И? Это вы к чему?

к этой фразе
Цитата(AHTOXA @ Aug 23 2012, 19:28) *
Ой ли? Сдаётся мне, что ключ -j появился далеко не сразу. ...

более 20 лет, этот ключик "-j", у gnu make существует, новым его не назвать.
AHTOXA
Цитата(e-serg @ Aug 28 2012, 11:30) *
более 20 лет, этот ключик "-j", у gnu make существует, новым его не назвать.

Я и не называл его новым. И появился он таки далеко не сразу. Так что всё чёткоsm.gif
ReAl
Цитата(AHTOXA @ Aug 24 2012, 11:03) *
Я считаю это большой глупостью авторов make.
Вот что-то мне в этой фразе не понравилось :-)
Это 50% пинка, вся остальная тема — ещё 50%
Всем спасибо, пинок застаивл еще раз заглянуть в документацию :-)
Код
.NOTPARALLEL: start dirs clean reset OK


:-(
Тьху, не оно :-(
Разница во времени на мелком проекте небольшая и линкеовка с LTO занимает около половины, без LTO и с time стало хорошо видно, что полностью. отрубается параллельность. Ну и не дочитался сразу, что зависимости к этой цели по барабану, главное, что она есть в Makefile.
Ну, значит, нужен feature request на .SEQUENTIAL и доброволец на реализацию :-)


Всё равно было полезно поговорить :-)
сlean я делаю отдельно вручную.
Но прошёлся по более-менее актуальным для себя Makefile, в одном старом было rebuild, в нескольких других (все в примерах scmRTOS) цель build.

Заменил на уже предложенное мной
Код
build:
    $(MAKE) clean
    $(MAKE)
В том числе во всех CortexM3/GCC примерах и вбросил изменения в репозиторий.
AHTOXA
Цитата(ReAl @ Aug 28 2012, 19:34) *
Тьху, не оно :-(

Угу, это я уже тоже смотрелsad.gif
Цитата(ReAl @ Aug 28 2012, 19:34) *
В том числе во всех CortexM3/GCC примерах и вбросил изменения в репозиторий.

Спасибо!
MBR
Где-то в гентушных факах рекомендовалось устанавливать значение -j в 2 * N + 1, где N - количество независимых потоков.
mdmitry
Цитата(ReAl @ Aug 28 2012, 17:34) *
Код
build:
    $(MAKE) clean
    $(MAKE)

Скажите, пожалуйста, в чем смысл в цели build _всегда_ делать clean? Если меняется код только в одном файле, то компилировать надо только его, а линковать всё, но в этом случае пересобирается весь проект. Время сборки увеличивается.
AHTOXA
Цитата(mdmitry @ Sep 10 2012, 16:21) *
Скажите, пожалуйста, в чем смысл в цели build _всегда_ делать clean?

Потому что цель такая - полная пересборка. Для выборочной пересборки, о которой вы говорите, есть цель all.
mdmitry
Цитата(AHTOXA @ Sep 10 2012, 15:28) *
Потому что цель такая - полная пересборка. Для выборочной пересборки, о которой вы говорите, есть цель all.


Цитата из makefile_template для Winavr
Код
# Default target.
all: begin gccversion sizebefore build sizeafter end

# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib

Мне понятно, что цель build является частью общей цели all. На мой взгляд логично исходя из названия целей.
Скажите, пожалуйста, какие причины причины побудили Вас сделать иначе?
Дмитриос
Мне кажется существенным выгрышем по сборке было бы использование чего нить такого, что не заставляет пересобирать ВЕСЬ проект.

1. файлы зависимостей *.d
2. выделение части проекта в статические библиотеки
3. Linux как-то быстрее собирает (ну это наверное совсем координальное решение) windows ещё со времён дискетки как-то
не любит кучи мелких файлов да и антивирусник тут постоянно вмешивается.

можно в ручную писать make a можно ещё какие средства для его генерации использовать
студии разработки и стемы типа CMAKE и не сильно ломать
ReAl
Цитата(mdmitry @ Sep 10 2012, 20:40) *
Цитата из makefile_template для Winavr
...
Мне понятно, что цель build является частью общей цели all. На мой взгляд логично исходя из названия целей.
Скажите, пожалуйста, какие причины причины побудили Вас сделать иначе?
"иначе" -- это цель, которую можно было бы назвать rebuild («Потому что цель такая - полная пересборка.») назвать все-таки build ?
Ну, например, потому, что человек считает простой вызов make -- так, по дороге отладочным.
А вот когда нужно сделать build программы (пишут же «XXX version YYY build ZZZ» а не «rebuild ZZZ»), то тогда и вызывается make build.

Впрочем, я сам больше склоняюсь к имени rebuild :-)

Кстати, по поводу make clean all и -j. Code::Blocks по кнопке «пересобрать» сам последовательно запускает make clean и make, поэтому ничего и не вылазит :-)

Цитата(Дмитриос @ Sep 11 2012, 01:37) *
Мне кажется существенным выгрышем по сборке было бы использование чего нить такого, что не заставляет пересобирать ВЕСЬ проект.
А никто тут и не пересобирает ВЕСЬ проект при каждом изменении одной буквы в листовом файле проекта. Это так, в нескольких сообщениях обсуждается название цели, которая используется для (выделенной в отдельную цель, нечастой, осознанно вызываемой) полной пересборки.
AHTOXA
Цитата(mdmitry @ Sep 10 2012, 23:40) *
Код
# Default target.
all: begin gccversion sizebefore build sizeafter end

Как мы недавно выяснили, это работает криво.
Цитата(mdmitry @ Sep 10 2012, 23:40) *
Мне понятно, что цель build является частью общей цели all. На мой взгляд логично исходя из названия целей.
Скажите, пожалуйста, какие причины причины побудили Вас сделать иначе?

sm.gif Дело в том, что я не читал "makefile_template для Winavr", когда писал этот makefile. И мне показалось логичным, что вызов "make" пересобирает только изменившиеся файлы, а вызов "make build" - полностью пересобирает проект.
Цитата(ReAl @ Sep 11 2012, 08:26) *
Впрочем, я сам больше склоняюсь к имени rebuild :-)

build - корочеsm.gif
Я сейчас задумался, почему build. Решил, что это из борланд паскаля, там было Make (F9) и Build.
mdmitry
Цитата(AHTOXA @ Sep 11 2012, 06:46) *
Как мы недавно выяснили, это работает криво.

Так наверно по аналогии:
Код
all:    
    $(MAKE) begin
    $(MAKE) gccversion
        $(MAKE) sizebefore
        $(MAKE) build
        $(MAKE) sizeafter
        $(MAKE) end

Цель build аналогично. Надо проверять, это предположение.

Добавлю по названиям целей: в makefile файлах, которые я видел (linux) отдельно имелась цель clean и она не вызывалась автоматически при пострении проекта. Для сборки ядра всегда руками вызываю make clean. Наверно, у меня с linux'а сформировались стереотипы по названиям целей. Дискуссию на эту тему можно и закрыть. Дело в названии.
MBR
я тоже плюсую за all и clean. Причем, не забываем добавлять в .PHONY. Как-то устоявшийся стандарт.
AHTOXA
all и clean и так есть. Речь про
Код
build: clean all

Вернее, теперь уже
Код
build:
    $(MAKE) clean
    $(MAKE) all
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.