Как вы заставляете make-файл перестраивать цель

184

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

dnetdev11 ~ # make
make: `release' is up to date.

Как заставить make-файл перестроить цель?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

Примечание: имена удалены, чтобы защитить невинных

Редактировать: Финал Фиксированная версия:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib
Lodle
источник
Лодль, так как это часто посещаемый вопрос, хотели бы вы отредактировать вопрос, чтобы он был более современным? (Похоже, это .PHONYбыла не единственная ваша проблема, и вы не должны редактировать решение в вопросе, или, по крайней мере, больше.)
Кейт М

Ответы:

23

Вы можете объявить одну или несколько ваших целей фальшивыми .

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

...

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

Дейв
источник
68
Этот ответ, хотя он «принят» и высоко «одобрен», действительно не соответствует действительности. Во-первых, он говорит, что «объявлять цели фальшивыми», но затем он говорит, что «фальшивая цель - это не имя файла». Что ж, если ваша цель - файл, это противоречие в ответе. Во-вторых, он говорит, что «фальшивая цель не должна быть обязательной предпосылкой реального» - ну, а если это так? Исходный вопрос, не уточнил, если это так или нет. Правильный ответ - не объявлять ваши цели фальшивыми, а скорее объявить дополнительную фальшивую цель, а затем зависеть от целей, которые вы хотите восстановить.
Марк Галек,
2
@MarkGaleck. Когда в ответе говорится, что «фиктивная цель - это имя, которое на самом деле не является именем файла», он цитирует непосредственно из руководства по gcc make. Это совершенно правильно.
Drlolly
«Target» - это термин Make, который относится к тексту слева от двоеточия :, а не только к конечному результату, который вы хотите создать (например, ваш двоичный файл). В вопросе release, debug, cleanи installявляются мишенями MAKE, не xxx_utilили xxxcore.soили что - нибудь еще.
Кит М
728

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

Сикора
источник
4
@MarkKCowan Я полностью согласен! Это именно то, что я искал, а не какой-то обходной путь, как предлагает Дейв.
Мартен Бамелис
8
Недостаток этого подхода в том, что он просто создает слишком много вещей. В частности, с autotools, я видел, как он перезапускает конфигурацию .. Я хочу, чтобы решение на основе LD_PRELOAD можно было построить !!
vrdhn
да, и он может даже переписать файлы, которые вы не хотели! такие как глобальные системные библиотеки, которые появляются в зависимостях и перестраиваются и перезаписываются ...
Хулио Герра
18

Один прием, который раньше makeописывался в руководстве по Sun, - это использование (несуществующей) цели «.FORCE». Вы можете сделать это, создав файл force.mk, который содержит:

.FORCE:
$(FORCE_DEPS): .FORCE

Затем, если ваш существующий make-файл вызван makefile, вы можете запустить:

make FORCE_DEPS=release -f force.mk -f makefile release

Поскольку .FORCEничего не существует, все, что от него зависит, будет устаревшим и перестроенным.

Все это будет работать с любой версией make; в Linux у вас есть GNU Make и, следовательно, вы можете использовать цель .PHONY, как обсуждалось.

Также стоит подумать, почему makeрелиз считается актуальным. Это может быть потому, что у вас есть touch releaseкоманда среди выполненных команд; это может быть связано с тем, что существует файл или каталог с именем 'release', который существует и не имеет зависимостей и поэтому является актуальным. Тогда есть фактическая причина ...

Джонатан Леффлер
источник
14

Кто-то еще предложил .PHONY, который определенно правильно. .PHONY следует использовать для любого правила, для которого сравнение даты между входом и выходом недопустимо. Поскольку у вас нет целей в форме, output: inputвы должны использовать .PHONY для ВСЕХ из них!

Все это говорит о том, что вам, вероятно, следует определить некоторые переменные в верхней части вашего make-файла для различных имен файлов и определить настоящие правила make, которые имеют как входные, так и выходные разделы, чтобы вы могли использовать преимущества make, а именно то, что вы будете на самом деле только компилировать вещи, которые необходимо копмилировать!

Редактировать: добавлен пример. Не проверено, но это, как вы делаете .PHONY

.PHONY: clean    
clean:
    $(clean)
мольберт
источник
1
Ну, если бы вы могли показать мне пример, было бы неплохо. Я просто взломал его, пытаясь заставить плотину работать: P
Lodle
1
Расположение .PHONYцели не имеет значения. Это может быть где угодно Makefile.
Адриан W
5

Если я правильно помню, make использует временные метки (время изменения файла), чтобы определить, актуальна ли цель. Распространенным способом принудительного пересоздания является обновление этой метки времени с помощью команды «touch». Вы можете попробовать вызвать 'touch' в вашем make-файле, чтобы обновить временную метку одной из целей (возможно, одного из этих подфайлов), что может заставить Make выполнить эту команду.

poundifdef
источник
5

Этот простой метод позволит make-файлу нормально функционировать, когда форсирование нежелательно. Создайте новую цель под названием force в конце вашего make-файла . Сила цель будет касаться файла, используемая по умолчанию цели зависит. В приведенном ниже примере я добавил touch myprogram.cpp . Я также добавил рекурсивный вызов сделать . Это приведет к тому, что цель по умолчанию будет выполняться каждый раз, когда вы вводите make force .

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make
groko
источник
Вы никогда не должны использовать makeвнутри Makefile. Используйте $(MAKE)вместо этого.
Бенджамин Кроуфорд Ctrl-Alt-Tut
3

Я попробовал это, и это сработало для меня

добавить эти строки в Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

сохранить и теперь звонить

make new 

и он снова все перекомпилирует

Что произошло?

1) «новые» звонки чистые. 'clean' do 'rm', который удаляет все объектные файлы с расширением .o.

2) «новые» звонки «сделать». 'make' видит, что нет файлов '.o', поэтому он снова создает все '.o'. тогда компоновщик связывает все файлы .o в одном исполняемом файле

Удачи

hamaney
источник
1
В рецепте для newлучшего использования, $(MAKE)чемmake
Старынкевич
1

В соответствии с рекурсивной маркой Миллера, считающейся вредной, вам следует избегать звонков$(MAKE) ! В случае, если вы показываете, это безвредно, потому что на самом деле это не make-файл, а просто скрипт-обертка, который с таким же успехом мог бы быть написан в Shell. Но вы говорите, что продолжаете в том же духе на более глубоких уровнях рекурсии, так что вы, вероятно, столкнулись с проблемами, показанными в этом откровенном эссе.

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

ОТО, makepp был создан как решение этой проблемы. Вы можете писать свои make-файлы на уровне каталогов, но все они объединяются в полный обзор вашего проекта.

Но устаревшие make-файлы написаны рекурсивно. Таким образом, существует обходной путь, при котором $(MAKE)ничего не происходит, кроме как направить подзапросы обратно в основной процесс makepp. Только если вы делаете избыточные или, что еще хуже, противоречивые вещи между вашими субмейками, вы должны запросить --traditional-recursive-make(что, конечно, нарушает это преимущество makepp). Я не знаю других ваших make-файлов, но если они написаны правильно, с makepp необходимые перестройки должны выполняться автоматически, без необходимости каких-либо хаков, предложенных здесь другими.

Даниил
источник
Не ответил на вопрос: касательно основной точки и должен быть комментарий, а не ответ.
flungo
Возможно я не был достаточно ясен. С makepp весь этот make-файл-обертка не нужен. Зная точные зависимости (все, а не только то, что указано после :), он всегда будет восстанавливать при необходимости.
Даниэль
1

Если вам не нужно сохранять какие-либо результаты, которые вы уже успешно скомпилировали

nmake /A 

перестраивает все

CZahrobsky
источник
0

Это на самом деле зависит от цели. Если это фальшивая цель (то есть цель НЕ связана с файлом), вы должны объявить ее как .PHONY.

Однако, если цель не является фальшивой целью, но вы просто хотите по какой-то причине ее перестроить (например, когда вы используете макрос предварительной обработки __TIME__), вы должны использовать схему FORCE, описанную в ответах здесь.

Kostas
источник
0

Это уже упоминалось, но думал, что я мог бы добавить к использованию touch

Если вы touchскомпилировали все исходные файлы, touchкоманда изменит временные метки файла на системное времяtouch команда была выполнена.

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

Например: если проект был проектом c ++, то выполните touch *.cpp, затем makeснова запустите , и make должна перекомпилировать весь проект.

mrflash818
источник
0

Как указал абернер, в руководстве по сборке GNU есть рекомендуемое решение, которое использует «поддельную» цель для принудительного восстановления цели:

clean: FORCE
        rm $(objects)
FORCE: ; 

Это будет работать чисто, независимо от любых других зависимостей.

Я добавил точку с запятой в решение из руководства, иначе требуется пустая строка.

tdietel
источник
-1

В моей системе Linux (Centos 6.2) есть существенная разница между объявлением цели .PHONY и созданием фиктивной зависимости от FORCE, когда правило действительно создает файл, соответствующий цели. Когда файл должен быть заново создан каждый раз, ему требовалась как поддельная зависимость FORCE для файла, так и .PHONY для поддельной зависимости.

неправильно:

date > $@

право:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
UncleBob
источник
-1

make clean удаляет все уже скомпилированные объектные файлы.

Ханан Штейнгарт
источник