Як ви змушуєте makefile для відновлення цілі


184

У мене є makefile, який створює, а потім викликає інший makefile. Оскільки цей makefile викликає більше файлів, що робить його роботу, вона насправді не змінюється. Таким чином, він продовжує думати, що проект розроблений і актуальний.

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

Як змусити makefile відновити ціль?

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

Лодле, оскільки це питання, яке часто відвідують, ви хочете відредагувати питання, щоб бути сучаснішим? (Схоже, .PHONYце не була вашою єдиною проблемою, і ви насправді не повинні редагувати рішення в питанні, або, принаймні, не більше.)
Кіт М,

Відповіді:


23

Ви можете оголосити одну або декілька своїх цілей фальшивими .

Лідська ціль - це дійсно не ім’я файлу; швидше це лише назва рецепта, який потрібно виконати, коли ви робите явний запит. Існує дві причини використовувати хибну ціль: щоб уникнути конфлікту з однойменним файлом та покращити продуктивність.

...

Хитра ціль не повинна бути необхідною умовою справжнього цільового файлу; якщо це так, його рецепт буде працювати щоразу, коли make йтиме для оновлення цього файлу. Поки фальшива ціль ніколи не є необхідною умовою реальної цілі, рецепт фальшивої цілі буде виконуватися лише тоді, коли фальшива ціль є визначеною метою


68
Ця відповідь, хоча вона "прийнята" та високо "прихильна", справді не відповідає. По-перше, він говорить "оголосити цілі фальшивими", але потім каже, що "фальшива ціль насправді не є ім'ям файлу". Ну а якщо ваша мета - файл, то це суперечність у відповіді. По-друге, в ній сказано, що "хибна ціль не повинна бути обов'язковою умовою реального" - ну що робити, якщо вона є? Оригінальне запитання, не вказувало, є воно чи ні. Правильна відповідь полягає в тому, щоб не оголошувати ваші цілі фальшивими, а навпаки, оголошувати додаткову цілеспрямовану ціль, а потім, залежати від цілей, які ви хочете відновити, від цього.
Марк Галек

2
@MarkGaleck Коли у відповіді йдеться про те, що "підроблена ціль - це дійсно не ім'я файлу", вона цитується безпосередньо з керівництва gcc make. Це абсолютно правильно.
drlolly

"Ціль" - це термін Make, який посилається на текст зліва від двокрапки :, а не лише на кінцевий результат, який ви хочете створити (наприклад, ваш двійковий файл). У питанні release, debug, cleanі installє мішенями MAKE, що не xxx_utilабо xxxcore.soабо що - небудь ще.
Кіт М

728

-BПеремикач , щоб зробити, чий довгу форму --always-make, говорить makeНехтувати мітки час і зробити зазначені цілі. Це може перемогти мету використання make, але це може бути те, що вам потрібно.


4
@MarkKCowan Я повністю згоден! Цей параметр саме те, що я шукав, а не якийсь обхідний шлях, як пропонує Дейв.
Маартен Бамеліс

8
Застереження при такому підході полягає в тому, що він просто будує занадто багато речей. Зокрема, з автоінструментами я бачив, що це налаштування перезавантаження. Я хочу, щоб рішення, засновані на LD_PRELOAD, могли бути побудовані !!
vrdhn

так, і він може навіть переписати файли, яких ви не хотіли! наприклад, глобальні системні бібліотеки, які з'являються у залежностях і перебудовуються та перезаписуються ...
Julio Guerra

18

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

.FORCE:
$(FORCE_DEPS): .FORCE

Тоді, припускаючи, що ваш існуючий makefile викликається makefile, ви можете запустити:

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

Оскільки .FORCEйого не існує, все, що від нього залежить, буде застарілим та відтвореним.

Все це буде працювати з будь-якою версією make; в Linux у вас є GNU Make і тому можете використовувати ціль .PHONY, як обговорювалося.

Також варто подумати, чому makeвважає звільнення актуальним. Це може бути тому, що у вас є touch releaseкоманда серед команд, що виконуються; це може бути через те, що існує файл або каталог під назвою 'release', який існує і не має залежностей, і так актуально. Тоді є фактична причина ...


14

Хтось ще запропонував. FONON, що, безумовно, правильно. .PHONY слід використовувати для будь-якого правила, для якого порівняння дат між входом та висновком недійсне. Оскільки у вас немає цілей форми, output: inputви повинні використовувати. FONONY для всіх!

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

Правка: доданий приклад. Неперевірено, але це так, як у вас .PHONY

.PHONY: clean    
clean:
    $(clean)

1
Ну, якби ви могли показати мені приклад, було б добре. Атм я їх просто
зламає,

1
Розташування .PHONYцілі не має значення. Це може бути де завгодно Makefile.
Адріан Ш

5

Якщо я пам'ятаю правильно, "make" використовує часові позначки (час модифікації файлу), щоб визначити, чи є ціль актуальною чи ні. Поширений спосіб змусити повторну збірку - оновити цю часову позначку, використовуючи команду 'touch'. Ви можете спробувати викликати "touch" у вашому makefile для оновлення часової позначки однієї з цілей (можливо, однієї з цих підмайстрів), яка може змусити Make виконати цю команду.


5

Цей простий прийом дозволить makefile нормально функціонувати, коли форсування не бажане. Створіть нову ціль під назвою сила в кінці вашого файлу . Сила мета стосуватиметься файлу, яка використовується по замовчуванням мети залежить. У наведеному нижче прикладі я додав touch myprogram.cpp . Я також додав рекурсивний дзвінок, щоб зробити . Це спричинить досягнення цілі за замовчуванням щоразу, коли ви вводите силу .

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

force:
       touch yourProgram.cpp
       make

Ніколи не слід використовувати 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) "нові" дзвінки "зробити". 'змусити' побачити, що файлів '.o' немає, тому він знову створює всі .o. тоді лінкер пов'язує весь файл .o в один виконуваний вихід

Удачі


1
У рецепті для newкращого використання, $(MAKE)ніжmake
Базиле Старинкевич

1

Згідно з рекурсивним Міллером, який вважається шкідливим, вам слід уникати дзвінків$(MAKE) ! У випадку, що ви показуєте, це нешкідливо, адже це насправді не файл файлу, а лише сценарій обгортки, який, можливо, так само був написаний у Shell. Але ви кажете, що продовжуєте так на більш глибоких рекурсійних рівнях, тому ви, мабуть, стикалися з проблемами, показаними в цьому есе.

Звичайно, з GNU зробити це громіздко уникати. І хоча вони знають про цю проблему, це їх документований спосіб робити.

OTOH, makepp був створений як рішення цієї проблеми. Ви можете писати свої файли на рівні директорій, але всі вони збираються разом для повного перегляду вашого проекту.

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


Не відповів на питання: дотичний до основного пункту і повинен бути коментарем, а не відповіддю.
flungo

Можливо, я був недостатньо зрозумілий. З Makepp весь файл обгортки для обгортки не потрібен. Знаючи точні залежності (усі вони, а не лише те, що перераховано після :), вона завжди відбудовуватиметься, коли це буде необхідно.
Даніель

1

Якщо вам не потрібно зберігати жоден з результатів, які ви вже успішно склали

nmake /A 

відновлює всіх


0

Це насправді залежить від того, яка мета. Якщо це фальшива ціль (тобто ціль НЕ пов'язана з файлом), слід оголосити її як .PHONY.

Якщо ж ціль не є фальшивою ціллю, але ви просто хочете її відновити з якихось причин (наприклад, коли ви використовуєте макрос попередньої обробки __TIME__), слід використовувати схему FORCE, описану у відповідях тут.



0

Про це вже згадувалося, але я думав, що можу додати до використання touch

Якщо ви маєте touchвсі вихідні файли для компілювання, touchкоманда змінює часові позначки файлу на системний часtouch команди.

Вихідний файл timstamp - це те, що makeвикористовується для «знання» файлу, змінився, і його потрібно перекомпілювати

Наприклад: Якщо проект був проектом c ++, тоді зробіть touch *.cpp, запустіть makeще раз і зробіть слід перекомпілювати весь проект.


0

Як зазначав Аберньє, у посібнику з виготовлення GNU є рекомендоване рішення, яке використовує "підроблену" ціль для примусового відновлення цілі:

clean: FORCE
        rm $(objects)
FORCE: ; 

Це буде працювати чисто, незалежно від будь-яких інших залежностей.

Я додав крапку з комою до рішення з посібника, інакше потрібен порожній рядок.


-1

У моїй системі Linux (Centos 6.2) є значна різниця між оголошенням цілі .PHONY і створенням підробленої залежності від FORCE, коли правило насправді створює файл, що відповідає цілі. Коли файл потрібно щоразу регенерувати, він вимагав як підробленої залежності FORCE від файлу, так і .PHONY для підробленої залежності.

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

date > $@

правильно:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.