Makefile store powershell output in a variable for futher use

Viewed 224

System: Win10 with MinGW make

I am trying to store PowerShell output in a variable inside of the recipe, and unfortunately I've exhausted all options.

Variable that stores powershell command:

# Get newest package in the directory
LST_PKG := powershell "gci -Path . -File *.nipkg -Recurse -Name | sort creationtime | Select -First 1"

The output is builds\packages\srl-lut_1.2.0.32_windows_all.nipkg

The actual recipe that's not working (PKG_REL_PATH end up empty):

.PHONY: publish

publish: clean build package
ifeq ($(DEBUG), 1)
    @echo "Publishing a DEBUG package..."
    
#1. Copy package to feed repo
    $(eval PKG_REL_PATH = $(LST_PKG))
    cp $(ROOT_DIR)$(PKG_REL_PATH) $(TEST_FEED_REPO)
    
#2. Publish the package
    
else
    @echo "Publishing a RELEASE package..." 
endif

Partial output indicative of the issue:

"Publishing a DEBUG package..."
cp C:\Users\Public\Projects\SRL\lut\src\powershell "gci -Path . -File *.nipkg -Recurse -Name | sort creationtime | Select -First 1" \\raven\#Raven\SRLFeeds\SRL\Repo
'cp' is not recognized as an internal or external command,
operable program or batch file.
make: *** [makefile:78: publish] Error 1

It looks like LST_PKG does not expans and evaluate and just assigned as string to PKG_REL_PATH: cp C:\Users\Public\Projects\SRL\lut\src*powershell "gci -Path . -File .nipkg -Recurse -Name | sort creationtime | Select -First 1" \raven\#Raven\SRLFeeds\SRL\Repo

2 Answers
  1. Using make functions in recipes, like eval, is usually wrong.
  2. Your eval simply creates a copy of make variable LST_PKG named PKG_REL_PATH, it does not execute the powershell command.
  3. The error message you get seems to say that there is no cp command in the shell used by make to execute the recipes. This is quite strange. Do you know what shell make uses?

Assuming you find a way to solve the 3rd issue, you could simply try:

# Get newest package in the directory
LST_PKG := powershell "gci -Path . -File *.nipkg -Recurse -Name | sort creationtime | Select -First 1"
PKG_REL_PATH := $(shell $(LST_PKG))

The shell make function will pass the powershell command to the shell. The shell will execute it and the output will be assigned to the PKG_REL_PATH make variable. This will happen when make parses the Makefile. If you absolutely want this command to be executed at the same time as the publish recipe, what you need is more likely a shell variable:

publish: clean build package
ifeq ($(DEBUG), 1)
    @echo "Publishing a DEBUG package..."
    PKG_REL_PATH=$$($(LST_PKG)); \
    cp $(ROOT_DIR)"$$PKG_REL_PATH" $(TEST_FEED_REPO)    
else
    @echo "Publishing a RELEASE package..." 
endif

Note the $$ to escape the first expansion by make and pass $(powershell ...) or $PKG_REL_PATH to the shell. Without this the first expansion by make would eat the $ and what would be passed to the shell would not be what you want.

Note also the chaining of the shell commands with a semi-colon and the \ line continuation. They are absolutely needed to guarantee that the two commands are executed in the same shell. By default recipe lines are executed in different shell invocations (unless you use the GNU make .ONESHELL feature) and shell variables defined on one line are undefined in the next. So without the chaining and the line continuation the PKG_REL_PATH shell variable would not be defined in the cp... line.

Found a solution. First, I define a CMD-type copy command to be used instead on cp (at the beginning of the makefile, outside of all recipes:

# Copy a file from targed to destination
_CP = cmd /C copy

The correct expansion was archived by doing the following:

IS

publish:
ifeq ($(DEBUG), 1)
    @echo "Publishing a DEBUG package..."
    
#1. Copy package to feed repo
    $(_CP) "$(ROOT_DIR)$(shell $(_LST_PKG))" "$(TEST_FEED_REPO)"

#2. Publish the package
else
    @echo "Publishing a RELEASE package..." 
endif

WAS

publish: clean build package
ifeq ($(DEBUG), 1)
    @echo "Publishing a DEBUG package..."
    
#1. Copy package to feed repo
    $(eval PKG_REL_PATH = $(LST_PKG))
    cp $(ROOT_DIR)$(PKG_REL_PATH) $(TEST_FEED_REPO)
    
#2. Publish the package
    
else
    @echo "Publishing a RELEASE package..." 
endif

In summary, I used $(shell ...) inline evaluation to bypass all variable assignment which was giving the issue in the first place.

Related