我想在构建列表中添加我想要构建的软件包(如果尚未安装)。
目标是安装一些没有pip和本地源的Python软件包。我无法访问pip ...
所以我写了一个看起来像我的Makefile:
all: natsort foo bar foobar ...
natsort: natsort-4.0.4.tar.gz
tar xvzf $<
cd $(patsubst %.tar.gz,%, $<) && python setup.py install
rm -rf $(patsubst %.tar.gz,%, $<)
python -c 'import natsort'
echo -e "Installation of $< [done]\n" >> install.log
此实现的问题是每次运行Make命令时都会重建并重新安装所有软件包。我想检查模块是否已安装。我的想法是做这样的事情:
ifdef $(shell python -c 'import natsort')
all: natsort
endif
如何重写它以使其有效?
答案 0 :(得分:2)
你绝对可以做那样的事情。但是每次运行make
时,它都会“花费”shell调用和python调用,并且成本相对较高。
基本上,有两种方法可以以更便宜的方式做你想做的事。
配方中的印章文件和短路逻辑。
邮票文件方法基本上就是你所拥有的,除了你将touch $@
添加到食谱的末尾。
natsort: natsort-4.0.4.tar.gz
tar xvzf $<
cd $(patsubst %.tar.gz,%, $<) && python setup.py install
rm -rf $(patsubst %.tar.gz,%, $<)
python -c 'import natsort'
echo -e "Installation of $< [done]\n" >> install.log
touch $@
这样,第一次运行配方时会创建标记文件,直到natsort-4.0.4.tar.gz
比标记文件更新或标记文件被删除,配方才会再次运行。
请注意第二点。删除戳记文件,然后重新安装。
这就是短路逻辑解决方案所解决的问题。
而不是多个命令的原始规则,而是将它全部包装在一个命令中(这是可选的,但可以节省重复的检查成本),并在进行任何工作之前检查要安装的模块。
natsort: natsort-4.0.4.tar.gz
if ! python -c 'import natsort'; then \
tar xvzf $< || exit 1; \
cd $(patsubst %.tar.gz,%, $<) && python setup.py install || exit 1; \
rm -rf $(patsubst %.tar.gz,%, $<); \
python -c 'import natsort' || exit 1; \
echo -e "Installation of $< [done]\n" >> install.log; \
fi
请注意需要添加|| exit 1
,因为我们不再需要为我们处理。另请注意,现在总是运行规则(我们应该标记natsort
和.PHONY
),但在最常见的情况下,它会在if
测试后停止
所有人都说你可以结合这些方法来实现两全其美。
natsort: natsort-4.0.4.tar.gz
if ! python -c 'import natsort'; then \
tar xvzf $< || exit 1; \
cd $(patsubst %.tar.gz,%, $<) && python setup.py install || exit 1; \
rm -rf $(patsubst %.tar.gz,%, $<); \
python -c 'import natsort' || exit 1; \
echo -e "Installation of $< [done]\n" >> install.log; \
fi
touch $@
你可以从两种方法中获益。第一次运行make
时,natsort
文件不存在,并且运行配方。未安装natsort
,因此if
测试失败并进行安装。之后natsort
文件touch
编辑。安装下次make时natsort
比natsort-4.0.4.tar.gz
更新,因此make
认为它没有任何关系。如果由于某种原因,您删除natsort
文件,则下次make
运行时会检查模块是否存在,跳过安装并touch
es natsort
文件再次恢复同步。