How to assign the output of a command to a Makefile variable

后端 未结 7 1121
生来不讨喜
生来不讨喜 2020-12-02 05:11

I need to execute some make rules conditionally, only if the Python installed is greater than a certain version (say 2.5).

I thought I could do something like execut

相关标签:
7条回答
  • 2020-12-02 05:22

    Beware of recipes like this

    target:
        MY_ID=$(GENERATE_ID);
        echo $MY_ID;
    

    It does two things wrong. The first line in the recipe is executed in a separate shell instance from the second line. The variable is lost in the meantime. Second thing wrong is that the $ is not escaped.

    target:
        MY_ID=$(GENERATE_ID); \
        echo $$MY_ID;
    

    Both problems have been fixed and the variable is useable. The backslash combines both lines to run in one single shell, hence the setting of the variable and the reading of the variable afterwords, works.

    I realize the original post said how to get the results of a shell command into a MAKE variable, and this answer shows how to get it into a shell variable. But other readers may benefit.

    One final improvement, if the consumer expects an "environment variable" to be set, then you have to export it.

    my_shell_script
        echo $MY_ID
    

    would need this in the makefile

    target:
        export MY_ID=$(GENERATE_ID); \
        ./my_shell_script;
    

    Hope that helps someone. In general, one should avoid doing any real work outside of recipes, because if someone use the makefile with '--dry-run' option, to only SEE what it will do, it won't have any undesirable side effects. Every $(shell) call is evaluated at compile time and some real work could accidentally be done. Better to leave the real work, like generating ids, to the inside of the recipes when possible.

    0 讨论(0)
  • 2020-12-02 05:29

    Wrapping the assignment in an eval is working for me.

    # dependency on .PHONY prevents Make from 
    # thinking there's `nothing to be done`
    set_opts: .PHONY
      $(eval DOCKER_OPTS = -v $(shell mktemp -d -p /scratch):/output)
    
    0 讨论(0)
  • 2020-12-02 05:37

    Use the Make shell builtin like in MY_VAR=$(shell echo whatever)

    me@Zack:~$make
    MY_VAR IS whatever
    

    me@Zack:~$ cat Makefile 
    MY_VAR := $(shell echo whatever)
    
    all:
        @echo MY_VAR IS $(MY_VAR)
    
    0 讨论(0)
  • 2020-12-02 05:41

    In the below example, I have stored the Makefile folder path to LOCAL_PKG_DIR and then use LOCAL_PKG_DIR variable in targets.

    Makefile:

    LOCAL_PKG_DIR := $(shell eval pwd)
    
    .PHONY: print
    print:
        @echo $(LOCAL_PKG_DIR)
    

    Terminal output:

    $ make print
    /home/amrit/folder
    
    0 讨论(0)
  • 2020-12-02 05:44

    Here's a bit more complicated example with piping and variable assignment inside recipe:

    getpodname:
        # Getting pod name
        @eval $$(minikube docker-env) ;\
        $(eval PODNAME=$(shell sh -c "kubectl get pods | grep profile-posts-api | grep Running" | awk '{print $$1}'))
        echo $(PODNAME)
    
    0 讨论(0)
  • 2020-12-02 05:44

    With GNU Make, you can use shell and eval to store, run, and assign output from arbitrary command line invocations. The difference between the example below and those which use := is the := assignment happens once (when it is encountered) and for all. Recursively expanded variables set with = are a bit more "lazy"; references to other variables remain until the variable itself is referenced, and the subsequent recursive expansion takes place each time the variable is referenced, which is desirable for making "consistent, callable, snippets". See the manual on setting variables for more info.

    # Generate a random number.
    # This is not run initially.
    GENERATE_ID = $(shell od -vAn -N2 -tu2 < /dev/urandom)
    
    # Generate a random number, and assign it to MY_ID
    # This is not run initially.
    SET_ID = $(eval MY_ID=$(GENERATE_ID))
    
    # You can use .PHONY to tell make that we aren't building a target output file
    .PHONY: mytarget
    mytarget:
    # This is empty when we begin
        @echo $(MY_ID)
    # This recursively expands SET_ID, which calls the shell command and sets MY_ID
        $(SET_ID)
    # This will now be a random number
        @echo $(MY_ID)
    # Recursively expand SET_ID again, which calls the shell command (again) and sets MY_ID (again)
        $(SET_ID)
    # This will now be a different random number
        @echo $(MY_ID)
    
    0 讨论(0)
提交回复
热议问题