Перерахуйте цілі / цілі в GNU, які містять змінні у своєму визначенні


100

У мене досить великий makefile, який створює ряд цілей на льоту, обчислюючи імена зі змінних. (наприклад, foo $ (VAR): $ (PREREQS)). Чи є якийсь спосіб переконати gnu, щоб виплюнути список цілей після того, як розширив ці змінні?

Я хотів би мати можливість отримати цілі для атрибутивного makefile. Я намагаюся написати функцію завершення для своєї оболонки.

Відповіді:


79

Чи можете ви проаналізувати вихід з make -pn(тобто make --print-data-base --dry-run)? Він друкує всі змінні, правила, неявні правила та команди, які будуть виконуватись з ретельними деталями.


Ця відповідь виглядає набагато приємніше, ніж інша.
Метт Столяр

Я згоден, що це набагато приємніше. Ще більше роботи, ніж я сподівався, але я збираюся відзначити це як відповідь, оскільки нічого іншого не здається розумним, і GNU make не має зручного прапора для того, що я хочу.
BitShifter

6
Майте на увазі, що вихід може залежати від заданої вами цілі, якщо ваш Makefile генерує цілі динамічно. Вихід може також залежати від значень змінних середовища або робити змінні, задані командою make.
reinierpost

6
Мені подобається стислість. +1 Додав власний спін (описаний у відповіді нижче):make -pn | sed -rn '/^[^# \t\.%].*:[^=]?/p'
Джеймі

Запропонуйте make -pnr. -rВидаляє приховані правила.
sjbx

114
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'     

Взятий із завершення створення аргументу, який працює як шарм.


2
Я намагався зробити псевдонім для цього, розміщуючи його в подвійних лапках, але це просто призводить до того, що у awk є синтаксична помилка на першій комі ... будь-які думки про те, як правильно уникнути цього псевдоніма оболонки (bash)?
drfrogsplat

3
Я думаю, що це має щось спільне з тим, де це визначено. Я думаю, якщо він визначений як псевдонім, його робочий каталог стає каталогом, де він визначений, і, мабуть, частина awk не любить крапку в прихованих каталогах. Визначення функції працює.
Ібрагім

Я просто помістив його в сценарій оболонки, ~/binа не використовував псевдонім. Чудово працює; Дякую!
mpontillo

3
Псевдонім, alias mkl="make -qp | awk -F':' '/^[a-zA-Z0-9][^\$#\/\t=]*:([^=]|\$)/ {split(\$1,A,/ /);for(i in A)print A[i]}' | sort"який допоможе вам заощадити 2 хвилини цитування ігор :-)
Ciro Santilli 郝海东 冠状 病 事件 事件 15

1
| sort -uвиглядає корисніше :)
sherpya

14

Я не впевнений, що це лише річ, яку це робить, але це добре:

make help


Це досить зручно, набагато простіше запам’ятати, ніж спеціальний псевдонім для одного з інших методів.
Ібрагім

8
Не дуже працює над GNU Make 3.81, напевно, ціль у ваших makefiles: "make: *** Немає правила робити
цільову`

8
Це просто викликає ціль "довідки" у Makefile. Якщо воно існує, воно надрукує щось (не повний перелік цілей), якщо його не існує (типова ситуація), воно випаде.
pfalcon

2
Хороша новина - це те, що cmake, здається, створює приємну легку для читання ціль допомоги.
Stéphane

Це круто! :) Ідіть cmake
Jeef

10

Кілька респондентів запропонували використовувати make -pn, які будуть друкувати базу даних правил, але нічого не виконувати - більш-менш. Проблема такого підходу полягає в тому, що -nвін все ще викликає всі рекурсивні дії, і він все ще робить набагато більше роботи, ніж потрібно, тому що він виводить кожну команду, яку він би викликав у звичайній збірці. Більш ефективним рішенням було б створити тривіальний makefile, dummy.mk з таким вмістом:

__all_targets__: ; #no-op

Тепер виклик make as make -p -f Makefile -f dummy.mk __all_targets__. У будь-якому суттєвому складі різниця в обсязі випуску продукції, виробленої маркою, є значною. Наприклад:

$ gmake -pn | wc
 138985 2632330 69612711
$ gmake -f Makefile -f /tmp/dummy.mk -pn __all_targets__ | wc
  21673   93437  878985

Час виконання також був значно кращим - 2.063 для першої версії, 0.059 для другої.


1
Ідеальна ідея, всі, хто працює з величезними системами побудови, оцінять її. Статистика для Android Gingerbread tree (не використовує рекурсивну марку, тому економія не величезна, просто хороша): " time make -pn | wc -l": 1338738 real 0m47.754s." time make -f Makefile -f dummy.mk -pn __all_targets__ | wc -l": 938621 real 0m40.219s.
pfalcon

Гарна думка. Сторінка людини для, makeздається, пропонує щось подібне, але доброзичливе, а самеmake -p -f/dev/null
Девід

@Поділіться, що це не спрацює: вказівка -f /dev/nullзапобіжить makeрозбору звичайних файлів, тому ви отримаєте роздруківку лише вбудованих правил. Ось чому моє рішення конкретизує -f Makefile -f dummy.mk. Але і цього недостатньо, тому що з -n, makeбуде продовжуватися і фактично також почне виконувати правила в makefile. На жаль, я не знаю жодних модифікацій, які б спростили рішення, як було представлено спочатку.
Ерік Мельський

Звичайно, ти маєш рацію. Однак на сторінці make man є помилка, оскільки в ній сказано: "Щоб надрукувати базу даних, не намагаючись переробити жодні файли, використовуйте make -p -f / dev / null"
Davide,

Трохи виправлення до мого попереднього коментаря: він повинен писати "... тому що без -n ..."
Ерік Мельський


7

Редагувати: FYI, сховище git завершення файлів debian в іншій відповіді тепер включає в себе розширену версію цього сценарію, пристосовану до випадків використання bash завершення.

#!/bin/bash

SCRIPT='
  /^# Make data base/,/^# Files/d             # skip until files section
  /^# Not a target/,+1          d             # following target isnt
  /^\.PHONY:/                   d             # special target
  /^\.SUFFIXES:/                d             # special target
  /^\.DEFAULT:/                 d             # special target
  /^\.PRECIOUS:/                d             # special target
  /^\.INTERMEDIATE:/            d             # special target
  /^\.SECONDARY:/               d             # special target
  /^\.SECONDEXPANSION/          d             # special target
  /^\.DELETE_ON_ERROR:/         d             # special target
  /^\.IGNORE:/                  d             # special target
  /^\.LOW_RESOLUTION_TIME:/     d             # special target
  /^\.SILENT:/                  d             # special target
  /^\.EXPORT_ALL_VARIABLES:/    d             # special target
  /^\.NOTPARALLEL:/             d             # special target
  /^\.ONESHELL:/                d             # special target
  /^\.POSIX:/                   d             # special target
  /^\.NOEXPORT:/                d             # special target
  /^\.MAKE:/                    d             # special target

# The stuff above here describes lines that are not
#  explicit targets or not targets other than special ones
# The stuff below here decides whether an explicit target
#  should be output.

  /^[^#\t:=%]+:([^=]|$)/ {                    # found target block
    h                                         # hold target
    d                                         # delete line
  }
  /^# File is an intermediate prerequisite/ { # nope
    s/^.*$//;x                                # unhold target
    d                                         # delete line
  }
  /^([^#]|$)/ {                               # end of target block
    s/^.*$//;x                                # unhold target
    s/:.*$//p                                 # write current target
    d                                         # hide any bugs
  }
'

make -npq .DEFAULT 2>/dev/null | sed -n -r "$SCRIPT" \
  | sort | uniq

Це набагато більш повний скрипт, ніж сценарій завершення debian bash, тому що він дає результати для згенерованих правил, саме про це запитує запитання, а верхній проголосований відповідь (сценарій завершення debian bash на сервері debian git) не надто далеко.

Це не оригінальний сценарій, з яким я пов’язаний, але він набагато простіший і швидший на дотик.


BTW, модники, якщо ця відповідь не повністю відповідає всій політиці через нюанс тексту, будь ласка, прокоментуйте її перед видаленням. Я буду вносити будь-які законні корективи, щоб це питання справді отримало повну і достовірну відповідь.
codehot

Як швидкий тест, я схопив вихідний код gcc і побіг ./configure && time ~ / makecomp.sh | wc -l де ~ / makecomp.sh - моя відповідь. ... Налаштувати вихід ... config.status: створення Makefile 3312 реального 0m0.401s користувача 0m0.412s sys 0m0.028s
codehot

В якості іншого тесту я використовував демонстраційний файл файлу codehot.blogspot.co.uk/2012/08/…, який генерує псевдо правила для побудови та перевірки пропусків тестових одиниць. Цей приклад використовує більше функцій make, ніж типовий міжплатформенний проект autoconf, тому сценарій у цій відповіді повертає 14 реальних цілей, тоді як завершення bash для make on ubuntu повертає лише два корисні правила, а потім 5 вихідних файлів.
codehot

4

Це код псевдоніма, заснований на рішенні Todd Hodes

alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'

3

Це дасть хороший вихід:

make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort


2

Гадаю, я трохи запізнююся на цю партію, але якщо ви шукаєте певну команду, ви можете спробувати

make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'

Це здебільшого працює, хоча воно все ще може включати деякі нецільові речі, як-от vpathдиректива. Якщо ви не залежите від makeвбудованих правил, ви можете використовувати make -qpRяк першу команду в конвеєрі.


Я спробував це з freetz (.org). Перераховано багато включених файлів і не перелічено всіх цілей.
Роберт Сімер

1

Рубіновий розчин:

`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}

1

Я працюю на Solaris 10 anda turbo C shell. Дане рішення не працює для мого проекту makefile. навіть після зміни командного рядка в синтаксис tcsh. Однак я дізнався, що ви можете отримати просте рішення за допомогою

remake --tasks | grep -v "clean some static output or just grep tabs on start of line" | awk ´{print $1}´

перероблена версія:

remake --version

є

GNU Make 3.82+dbg0.8
Built for sparc-sun-sparc2-9

та деякі інші неважливі дані версії


0

Я пішов шукати те саме питання і придумав цю спіну:

make -pn | sed -rn '/^[^# \t\.%].*:/p'

При цьому видаляються всі рядки коментарів, правила шаблону (рядки, що починаються з вкладок), усі внутрішні елементи (приклад .c.oта %.o: %.cшаблони).


не читав коментар із прийнятої відповіді: +1 для відповіді Джека ... gist.github.com/777954 - pvandenberk 13 січня о 14:47
Джеймі

0

Знайшов це рішення в іншій темі:

sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\""

Ви також можете додати його до свого Makefile:

list:
    sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\\""

І виконати make list.


-1

Звичайно, але коли ти хочеш, щоб вони їх виплюнули?

Щоб повідомити ім'я цілі, коли воно запускає правило, введіть рядок у правило:

foo$(VAR): $(PREREQS)
    @echo now making the foo target: $@
    do_other_stuff...

Щоб виплюнути їх все одразу, ви можете зробити окрему ціль PHONY:

.PHONY: show_vars
show_vars:
    @echo foo$(VAR)
    @echo bar$(PARAM) blah$(FLAG)
    # and so on

І це може бути передумовою вашої цілі за замовчуванням:

all: show_vars
    ...

РЕДАКТУВАННЯ:
Ви хочете, щоб показати всі можливі цілі довільного makefile, який, напевно, означає не нав'язливий. Ну...

Щоб зробити це точно і бути в змозі впоратися зі складними файлами, наприклад із використанням правил, побудованих на evalоператорах, вам доведеться написати щось наближене до емулятора Make. Непримітний.

Щоб побачити цілі простих правил, ви можете написати файл makefile, який буде виконувати роль сканера makefile, оперуючи довільним makefile:

  1. Отримати всі цільові імена з makefile за допомогою sed.
  2. `include` makefile для того, щоб використовувати його для розширення змінних.
  3. Використовуйте `show_%:; echo $$ * `для друку всіх цілей

Це було б вражаючий твір. Ви впевнені, що мета варта ваших зусиль?


Не зовсім те, що я хочу. Мені б хотілося зробити так, щоб скласти список цілей для довільного файлу, який у мене може бути. Я намагаюся написати функцію завершення аргументу для своєї оболонки, і я не можу розраховувати на те, що файли мають будь-яку розумну допомогу.
BitShifter

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