Чтение обновленного файла в функции Makefile - PullRequest
0 голосов
/ 18 января 2019

Я хочу прочитать часть строки (некоторый номер версии) из файла version. Эта функциональность добавлена ​​в функцию make-файла. Перед этим я обновляю файл с новым номером версии. Но когда я пытаюсь присвоить эту новую версию некоторой переменной, она читает старый номер версии.

Просто чтобы убедиться, я добавил команду cat verison для проверки содержимого файла.

Ниже приведено содержимое файлов, которые я написал.

файл: версия

me@linux:temp$ cat version 
PROC_V7.1.2.3

файл: Makefile

me@linux:temp$ cat Makefile 
include $(shell pwd)/$(wildcard *.mk)

.PHONY: firmware
firmware:
    $(call version_replace, 100)

файл: image.mk

me@linux:temp$ cat image.mk 
define version_replace
    cat version
    sed -i 's/V7/V177/g' version
    cat version
    $(eval NEW_VER:=$(shell cat version | cut -d '_' -f 2 ))
    echo $(NEW_VER)
endef

Поэтому, когда я сделал make firmware, новая переменная дает старое значение V7.1.2.3 вместо V177.1.2.3.

me@linux:temp$ make firmware 
cat version
PROC_V7.1.2.3
sed -i 's/V7/V177/g' version
cat version
PROC_V177.1.2.3
NEW_VER=V7.1.2.3
echo V7.1.2.3
V7.1.2.3

Насколько я понимаю, все назначения, выполняемые первыми, и NEW_VER уже заполнены старым номером версии при вызове функции version_replace.

Так как мне прочитать обновленный номер версии из файла в функции make file?

Ответы [ 4 ]

0 голосов
/ 21 января 2019

Это поведение make.make раскроет рецепты цели перед ее выполнением.

Рецепт $(eval NEW_VER:=$(shell cat version | cut -d '_' -f 2 )) будет расширен, а переменная NEW_VER будет сохранена в списке переменных со значением V7.1.2.3 (который из файла версии).Поскольку версия еще не обновлена ​​в файле версии.Рецепт echo $(NEW_VER) будет заменен на echo V7.1.2.3.

Перед выполнением рецепты цели firmware будут

cat version
sed -i 's/V7/V177/g' version
cat version
echo V7.1.2.3

Следовательно, в конце на выходе выводится печатьстарая версия.

Чтобы это работало, поставьте две разные цели.Один для изменения версии в файле и другой для чтения.

Makefile:

all: replace_version read_version

replace_version:
    cat version
    sed -i 's/V7/V177/g' version

read_version:
    cat version
    $(eval NEW_VER:=$(shell cat version | cut -d '_' -f 2 ))
    echo $(NEW_VER)

Есть еще один возможный способ заставить эту работус одной целью.Измените команду sed как расширяемый рецепт

Makefile:

firmware:
        $(call version_replace, 100)

image.mk

define version_replace
        $(shell sed -i 's/V7/V177/g' version)
        $(eval NEW_VER:=$(shell cat version | cut -d '_' -f 2 ))
        echo $(NEW_VER)
endef
0 голосов
/ 18 января 2019

Я бы разделил две вещи так:

.PHONY: firmware
firmware: version
    # replace with firmware generation command that reads from $<
    @echo FIRMWARE $@ $<

.PHONY: version
version:
    # replace with version update command (sequence)
    @echo VERSION $@

Построение firmware приведет к следующей последовательности:

$ make firmware
# replace with version update command (sequence)
VERSION version
# replace with firmware generation command that reads from version
FIRMWARE firmware version

РЕДАКТИРОВАТЬ: ваше требование для различных приращений версии должно быть переменной, которая контролирует командные строки для цели version:, например, make VERSION_INCREMENT=200 firmware.

0 голосов
/ 18 января 2019

Ваше явление может быть сведено к простому, хотя и загадочному примеру:

MY_OUTPUT := First line
.PHONY: foo
foo:
    @echo $(MY_OUTPUT)
    $(eval MY_OUTPUT := $(shell $(info eval-time) echo Second line))
    @echo $(MY_OUTPUT)
    $(shell read -p "Hit return:")

Выход:

$ make foo
eval-time
Hit return:

... ожидание нажатия клавиши

First line
Second line

Оценка рецепта выглядит следующим образом: Выделите буфер строк, которые будут содержать строки команд окончательного рецепта без синтаксиса make. Затем пройдитесь по всем строкам рецепта, выполните весь известный синтаксис make, удалите один уровень из всех кавычек ($$), выполните вещи $(eval) и запишите строки в буфер. только затем перебирает итоговый список командных строк и выдает их sh по очереди. $(info) говорит нам, что строка аргумента уже была оценена заранее, что нарушает ваш предполагаемый порядок.

0 голосов
/ 18 января 2019

Может быть трудно заставить call работать с несколькими командами, как у вас, поэтому я считаю, что иногда проще (хотя и менее переносимо) вместо этого создать сценарий оболочки:

Makefile

EXEC := $(shell sh script.sh)
FILE := new_version
VERS := $(shell cat $(FILE))

.PHONY: firmware
firmware:
    $(info $(VERS))

script.sh

#!/bin/bash

sed 's/V7/V177/g' version | cut -d '_' -f 2 > new_version
# optional # mv new_version version

При желании вы можете перезаписать файл version, раскомментировав последнюю строку в скрипте и заменив переменную FILE в Makefile на version.

$ make firmware
V177.1.2.3
make: Nothing to be done for `firmware'.
...