简体   繁体   中英

Creating variable from bash command output in makefile

Hello I would like to ask how I can create bash variable in makefile. Below code does work but variable "targets" keeps being empty. How I can actually create "targets" and "current_target" variables in makefile?. Problem is that I have to create this variables from actual bash commands.

SHELL=/bin/bash
...
MAIN_APPS = 01_prep 02_prep 03_prep 04_prep 05_prep
foo : .check_targets .check_segment 
    @for f in $(MAIN_APPS) ; do \
        targets=$(expr $(last_target) + 1); \
        echo $(targets) + 1; \
        curent_target=$(expr "$(echo $(f) | head -c 2) + 0"); \
        if [ $(targets) = $(current_target)]; then \
            break; \
        else \
            make $(f); \
        fi \
    done

output:

make foo last_target="02" segm=KI
+ 1

What I want to do is to make targets from my makefile which actually starts from 01 to 05 if I pass an argument last_target="05"

You mix up between make variables and shell variables. And you did not consider that make expands the recipes before passing them to the shell, reason why you frequently need to use $$ instead of $ . Or, for command expansion, `...` instead of $(...) . You are also using double quotes where you shouldn't ( expr "..." ). Finally, you use make in your recipe, which is not a good idea. You should use $(MAKE) (see the How the MAKE Variable Works section of the GNU make manual for the details).

Try the following (not tested) maybe:

SHELL=/bin/bash
...
MAIN_APPS = 01_prep 02_prep 03_prep 04_prep 05_prep
foo : .check_targets .check_segment 
    @for f in $(MAIN_APPS) ; do \
        targets=`expr "$(last_target)" + 1`; \
        echo "$$targets + 1"; \
        tmp=`echo "$$f" | head -c 2`; \
        curent_target=`expr "$$tmp" + 0`; \
        if [ "$$targets" = "$$current_target" ]; then \
            break; \
        else \
            $(MAKE) "$$f"; \
        fi \
    done

But I am almost 100% convinced that you are trying to use make as a kind of scripting language instead of as a sophisticated build system. If I understand well you are trying to rebuild only a subset of your MAIN_APPS by specifying a last target number. You could probably achieve the same with a much more make-ish style:

TARGETS := $(shell printf '%02d_prep\n' $$(seq $(last_target)))

.PHONY: foo
foo: $(TARGETS) .check_targets .check_segment

And that's all, no complex recipe for foo . Nothing at all (except, of course, the rules to build .check_targets , .check_segment and all xx_prep targets, that you do not show).

Explanation: I used the $(shell ...) make function and a small shell script to initialize make variable TARGETS with 01_prep 02_prep ... up to $(last_target)_prep . As noted in the comments this shell script does not even require bash and would work with the default make shell (sh). So, if you do not have other good reasons to use bash, get rid of the SHELL=/bin/bash line and your Makefile will be a bit more portable.

Then, I declared foo as phony because you probably don't have a file named foo and, in case you have one, you probably want make to build foo anyway.

Finally, I declared $(TARGETS) , .check_targets , and .check_segment as prerequisites of foo . If you ask make to build foo and any of these prerequisites is out-of-date, make will build it using the rules you declared for it.

This is far more make-ish because it clearly tells make what depends on what instead of hiding it in a recipe. And make needs this to do its job correctly, which consist in comparing last modification dates of files to decide if something must be rebuilt or not. It also has extra benefits like, for instance, exploiting the parallelism of your computer to build several xx_prep in parallel if it is possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM