Проблема с циклом внутри make-файла - PullRequest
1 голос
/ 12 февраля 2011

Я пытаюсь реализовать логику для отображения хода сборки в make-файле.

Я могу успешно распечатать его для цели "simple" в make-файле, каскадно приведенном ниже.Однако, когда дело доходит до другой цели «для» в make-файле, что-то идет не так, и я не могу понять, что это такое.

Любая помощь будет очень признательна.

## BUILD is initially undefined
ifndef BUILD
# T estimates how many targets we are building by replacing BUILD with a special string
T := $(shell $(MAKE) progress --no-print-directory \
      -nrRf $(firstword $(MAKEFILE_LIST)) \
      BUILD="COUNTTHIS" | grep -c "COUNTTHIS")
## N is the target number
N := x
## incrementing counter
C = $(words $N)$(eval N := x $N)$(shell export $N)
## BUILD is now defined to show the progress, this also avoids redefining T in loop
BUILD = echo "`expr "   [\`expr $C '*' 100 / $T\`" : '.*\(....\)$$'`%]"
endif

MODULE_LIST  = module1
MODULE_LIST := $(MODULE_LIST) module2
MODULE_LIST := $(MODULE_LIST) module3
MODULE_LIST := $(MODULE_LIST) module4
MODULE_LIST := $(MODULE_LIST) module5

progress:
    @$(BUILD)
    @$(BUILD)
    @$(BUILD)
    @$(BUILD)
    @$(BUILD)

simple:
    # T=5 and C increases for every access
    @$(BUILD) "Cleaning Module \"module1\""
    @sleep 0.1
    @$(BUILD) "Cleaning Module \"module2\""
    @sleep 0.1
    @$(BUILD) "Cleaning Module \"module3\""
    @sleep 0.1
    @$(BUILD) "Cleaning Module \"module4\""
    @sleep 0.1
    @$(BUILD) "Cleaning Module \"module5\""
    @sleep 0.1

for:
    # T=1 and C increases for every access but not inside the for loop
    @for MODULE in $(MODULE_LIST); do \
        $(BUILD) "Cleaning Module \"$$MODULE\"" ; \
        sleep 0.1 ; \
    done

1 Ответ

4 голосов
/ 12 февраля 2011

Как вы отметили в своем комментарии, проблема в том, что цикл for выполняется внутри оболочки и поэтому не обновляет переменные Makefile (или, по крайней мере, не более одного раза, когда Make создает командную строку путем оценки ссылок на переменные).внутри него).

Единственное возможное решение, которое я вижу, это переместить вашу конструкцию цикла в Makefile.Попробуйте это:

## PRINT_PROGRESS is initially undefined
ifndef PRINT_PROGRESS
# T estimates how many targets we are building by replacing PRINT_PROGRESS with a special string
T := $(shell $(MAKE) $(MAKECMDGOALS) --no-print-directory \
      -rRf $(firstword $(MAKEFILE_LIST)) \
      PRINT_PROGRESS="echo COUNTTHIS" BUILD="test x ||" | grep -c "COUNTTHIS")
N := 1
## PRINT_PROGRESS is now defined to show the progress and update N
PRINT_PROGRESS = echo "`expr "   [\`expr $N '*' 100 / $T\`" : '.*\(....\)$$'`%]"$(eval N := $(shell expr $N + 1))
endif
ifndef BUILD
BUILD := #blank
endif

MODULE_LIST  = module1
MODULE_LIST += module2
MODULE_LIST += module3
MODULE_LIST += module4
MODULE_LIST += module5

simple:
    # T=5 and C increases for every access
    @$(PRINT_PROGRESS) "Cleaning Module \"module1\""
    @$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
    @$(PRINT_PROGRESS) "Cleaning Module \"module2\""
    @$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
    @$(PRINT_PROGRESS) "Cleaning Module \"module3\""
    @$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
    @$(PRINT_PROGRESS) "Cleaning Module \"module4\""
    @$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
    @$(PRINT_PROGRESS) "Cleaning Module \"module5\""
    @$(BUILD) { sleep 0.1 ; echo "doing some work" ; }

for:
    @$(foreach MODULE,$(MODULE_LIST),\
        $(PRINT_PROGRESS) "Cleaning Module \"$(MODULE)\"" ; \
        $(BUILD) { \
            sleep 0.1 ; \
            echo "doing some work" ; \
        } ; \
    )

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

Решение, которое кажется правдоподобным на первый взгляд, состоит в export N из make-файла и разработке команды PRINT_PROGRESSтак что N всегда обновляется как переменная окружения.Я не смог найти способ заставить эту работу работать, так как для этого требуется какой-то способ получить обновленное N значение назад в Make после после командынаписано, так что отдельные команды все еще работают.


Редактировать: Вывод при запуске точного сценария выше (с исправленными отступами табуляции), плюс используемые версии:

jpab@oberon : /memtmp
$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for x86_64-pc-linux-gnu

jpab@oberon : /memtmp
$ bash --version
GNU bash, version 4.1.5(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

jpab@oberon : /memtmp
$ make
# T=5 and C increases for every access
 [20%] Cleaning Module "module1"
doing some work
 [40%] Cleaning Module "module2"
doing some work
 [60%] Cleaning Module "module3"
doing some work
 [80%] Cleaning Module "module4"
doing some work
[100%] Cleaning Module "module5"
doing some work

jpab@oberon : /memtmp
$ make for
 [20%] Cleaning Module "module1"
doing some work
 [40%] Cleaning Module "module2"
doing some work
 [60%] Cleaning Module "module3"
doing some work
 [80%] Cleaning Module "module4"
doing some work
[100%] Cleaning Module "module5"
doing some work
...