Use shell commands in Makefile

I have several related packages in different git repositories, and each repository has several branches. It is a headache to package all of these packages during release period.

So I decided to create a new repository including all of the packages, and package the single branch at one time.

The simple project structure, we have several packages in pkg directory, and each has its own build.sh.

Since it is very simple, don't want to just add one Makefile for the whole thing, the content is like:

CWD:=$(shell pwd)
BUILD:=$(CWD)/build
PACKAGE_NAME:= app-$(shell date "+%Y%m%d%H%M").tar.gz

package:
        for pkg in $(ls -1 $(CWD)/pkgs); do \
                echo "### starting build package: $pkg..."; \
                $(CWD)/pkgs/$pkg/build.sh  $(BUILD); \
                echo "### finish build package $pkg"; \
                echo ; \
        done

And after I run make, I got no success.

for pkg in ; do \
        echo "### starting build package: kg..."; \
        /home/xxx/app/pkgs/kg/build.sh  /home/xxx/app/build; \
        echo "### finish build package kg"; \
        echo ; \
done

The ls command and $pkg are not executed/expanded correctly.

After some search I know that the shell commands in makefile may be invoked in one shell, and the statements will be expanded twice for shell commands, so we need double dollar signsfor shell variables.

Essentially, gmake scans the command-line for shell built-ins (like for and if) and “shell special characters” (like | and &). If none of these are present in the command-line, gmake will avoid the overhead of the shell invocation by invoking the command directly (literally just using execve to run the command).
[...]
gmake expands command-lines before executing them.

Command expansion is why you can use gmake features like variables (eg, $@) and functions (eg, $(foreach)) in the recipe. It is also why you must use double dollar signs if you want to reference shell variables in your recipe...

The correct statement is:

for pkg in $$(ls -1 $(CWD)/pkgs); do \
        echo "### starting build package: $$pkg..."; \
        $(CWD)/pkgs/$$pkg/build.sh  $(BUILD); \
        echo "### finish build package $$pkg"; \
        echo ; \
done

Since CWD and BUILD are variables in Makefile, so there are referenced with single dollar signs. And ls and pkg are variables in shell, theses variables are referenced with double dollar signs.

#shell #makefile