我有两个目标几乎相同:
# install node modules from package.json and bring npm-shrinkwrap.json up to date
npm-install:
ifndef SHRINKWRAP_BIN
$(error `npm-shrinkwrap` not found. Please run `sudo npm install -g npm-shrinkwrap`)
endif
$(NPM_BIN) install --no-shrinkwrap --loglevel=error --no-optional
$(NPM_BIN) prune --no-shrinkwrap --loglevel=error
$(NPM_BIN) dedupe --no-shrinkwrap --loglevel=error
npm-shrinkwrap --dev
touch $(NPM_TIMESTAMP)
# update npm dependencies to their latest version given the semver constraints and re-write npm-shrinkwrap file
npm-update:
ifndef SHRINKWRAP_BIN
$(error `npm-shrinkwrap` not found. Please run `sudo npm install -g npm-shrinkwrap`)
endif
$(NPM_BIN) update --save-dev --loglevel=error --no-optional
$(NPM_BIN) prune --no-shrinkwrap --loglevel=error
$(NPM_BIN) dedupe --no-shrinkwrap --loglevel=error
npm-shrinkwrap --dev
touch $(NPM_TIMESTAMP)有什么办法,我可以消除一些重复,让他们两个调用另一个目标?我不能仅仅向它们添加一个包含公共部分的先决条件,因为先决条件在命令之前运行,安装/更新位必须先运行(在prune/dedupe/收缩包装之前)。
发布于 2016-05-13 02:12:50
假设我正确地阅读了这一点,并且两者之间的区别只是npm-install中的单词install和npm-update中的update,那么这里的解决方案就是在您正在运行的命令中使用目标(或其中的一部分)。
就像这样:
# install node modules from package.json and bring npm-shrinkwrap.json up to date
npm-install npm-update:
ifndef SHRINKWRAP_BIN
$(error `npm-shrinkwrap` not found. Please run `sudo npm install -g npm-shrinkwrap`)
endif
$(NPM_BIN) $(subst npm-,,$@) --no-shrinkwrap --loglevel=error --no-optional
$(NPM_BIN) prune --no-shrinkwrap --loglevel=error
$(NPM_BIN) dedupe --no-shrinkwrap --loglevel=error
npm-shrinkwrap --dev
touch $(NPM_TIMESTAMP)您也可以使用$(word 2,$(subst -, ,$@))或$(patsubst npm-%,%,$@),或者由于上面没有将--no-shrinkwrap转换为--save-dev,您可以使用类似的方法(或者将上面的$@用法与类似于此的arg变量组合起来):
npm-install: command := install
npm-install: arg := --no-shrinkwrap
npm-update: command := update
npm-update: arg :=--save-dev
npm-install npm-update:
....
$(NPM_BIN) $(command) $(arg) --loglevel=error --no-optional
....发布于 2016-05-13 01:03:19
我对此有几个想法。第一种方法是只在Makefile中使用文本处理来显式地减少重复。定义多行宏,然后调用它。
define NPM_COMMON_STEPS
$(NPM_BIN) prune ...
$(NPM_BIN) dedupe ...
...
endef因为这没有参数,所以我们不必使用$(call ...)操作符。简单地说,在食谱中我们称之为:
$(NPM_COMMON_STEPS)还有其他的方法。您可以让虚拟的先决条件目标处理所有的逻辑,并根据谁在“调用”来切换它的某些部分。我们怎么知道呢?为什么,通过特定的目标变量!
这可以通过完整的Makefile来说明:
.PHONY: all common-target a-target b-target
all: a-target b-target
common-target:
$(if $(CALLED_FOR_A), echo called for a-target)
$(if $(CALLED_FOR_B), echo called for b-target)
echo common recipe
a-target: CALLED_FOR_A := y
a-target: common-target
b-target: CALLED_FOR_B := y
b-target: common-target测试:
$ make
echo called for a-target
called for a-target
echo common recipe
common recipe
$ make a-target
echo called for a-target
called for a-target
echo common recipe
common recipe
$ make b-target
echo called for b-target
called for b-target
echo common recipe
common recipe正如您所看到的,这里有一个缺点,如果我们更新目标all,那么GNU只执行一次共享公共规则。当代表a-target运行该规则时,它被认为是更新的,而不是为b-target运行的。
如果我们没有在相同的运行中更新两个目标,这并不重要,但同样,这是一个潜在的障碍:
$ make a-target b-target
echo called for a-target
called for a-target
echo common recipe
common recipe
make: Nothing to be done for `b-target'.因此,在使用这种伎俩之前,我会三思而后行。如果您永远不会在同一个调用中执行npm-update和npm-install,那么可以使用它。
以下是文本替换解决方案的完整示例:
.PHONY: all a-target b-target
all: a-target b-target
define COMMON
echo common recipe
endef
define COMMON_WITH_ARG
echo common recipe with arg 1 == $(1)
endef
a-target:
echo a-target
$(COMMON)
$(call COMMON_WITH_ARG,a)
echo a-done
b-target:
echo b-target
$(COMMON)
$(call COMMON_WITH_ARG,b)
echo b-done运行:
$ make
echo a-target
a-target
echo common recipe
common recipe
echo common recipe with arg 1 == a
common recipe with arg 1 == a
echo a-done
a-done
echo b-target
b-target
echo common recipe
common recipe
echo common recipe with arg 1 == b
common recipe with arg 1 == b
echo b-done
b-donehttps://stackoverflow.com/questions/37199299
复制相似问题