让Always每次运行时都调用一些依赖规则

时间:2018-06-24 13:47:37

标签: python makefile

我遇到的情况是需要远程运行一些python脚本,并且需要选择一些文件并将其复制到远程文件夹。我分两个阶段进行此操作。我将文件复制到临时文件夹,然后准备好发送存档。

我创建了makefile来使第一阶段自动化,但它似乎有些奇怪。生成文件如下所示:

# Makefile and user paths
mkfile_path = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
user_path = $(shell echo $$HOME)

# Dependencies
ENTDIR = entropy
BINDIR = binary-files
MODDIR = modules
NORTH = $(BINDIR)/north
SOUTH = $(BINDIR)/south
WEST = $(BINDIR)/west
DISK = $(MODDIR)/disk
GEN = $(MODDIR)/general
PROB = $(MODDIR)/probability
NLTK = nltk_data
METAVAR = obj-meta-vars

# Target
TARGET=scripts-to-run-remotely.tar.gz

# Rules
all : $(TARGET)
    @echo "Complete"

$(TARGET) : $(NORTH)/north.obj \
        $(SOUTH)/south.obj \
        $(WEST)/west.obj \
        $(ENTDIR)/mifunction.py \
        $(ENTDIR)/miopt.py \
        $(ENTDIR)/miprint.py \
        $(ENTDIR)/run-logs.py \
        $(DISK)/%.py \
        $(GEN)/%.py \
        $(PROB)/%.py \
        $(METAVAR)/%.obj \
        $(NLTK)
    tar -czf $(TARGET) $(ENTDIR)/* $(BINDIR)/* $(MODDIR)/* $(NLTK)/* $(METAVAR)/*

# Files
$(NORTH)/north.obj: $(NORTH)
    cp /home/user/Documents/python/$(NORTH)/north.obj ./$(NORTH)

$(SOUTH)/south.obj: $(SOUTH)
    cp /home/user/Documents/python/$(SOUTH)/south.obj ./$(SOUTH)

$(WEST)/west.obj: $(WEST)
    cp /home/user/Documents/python/$(WEST)/west.obj ./$(WEST)

$(DISK)/%.py: $(DISK)
    cp /home/user/Documents/python/$(DISK)/*.py ./$(DISK)

$(GEN)/%.py: $(GEN)
    cp /home/user/Documents/python/$(GEN)/*.py ./$(GEN)

$(PROB)/%.py: $(PROB)
    cp /home/user/Documents/python/$(PROB)/*.py ./$(PROB)

$(ENTDIR)/mifunction.py: $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/mifunction.py ./$(ENTDIR)

$(ENTDIR)/optmi.py: $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/miopt.py ./$(ENTDIR)

$(ENTDIR)/printmi.py: $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/miprint.py ./$(ENTDIR)

$(ENTDIR)/run-logs.py: $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/run-logs.py ./$(ENTDIR)

$(METAVAR)/%.obj: $(METAVAR)
    cp /home/user/Dropbox/data/outputs/$(METAVAR)/*.obj ./$(METAVAR)

# Folders
$(NORTH):
    mkdir -p $@

$(SOUTH):
    mkdir -p $@

$(WEST):
    mkdir -p $@

$(ENTDIR):
    mkdir -p $@

$(DISK):
    mkdir -p $@

$(GEN):
    mkdir -p $@

$(PROB):
    mkdir -p $@

$(METAVAR):
    mkdir -p $@

$(NLTK):
    mkdir -p $@
    @python3 -m nltk.downloader wordnet wordnet_ic averaged_perceptron_tagger -d $(mkfile_path)/$(NLTK)

clean:
    @rm -rf ./$(TARGET) ./$(ENTDIR) ./$(BINDIR) ./$(MODDIR) ./$(METAVAR) ./$(NLTK)
    @echo "All files and folders removed"

# Always run those:
.PHONY: all

我想问的第一件事是如何避免冗余;如果可能的话,如何避免重复代码的一部分。

第二件事是,当我第一次运行make时,它会遍历所有需要创建文件的规则,然后遍历所有需要复制文件的规则。当我再次运行make时,它调用与复制文件有关的规则:

cp /home/user/Documents/python/entropy/mifunction.py ./entropy
cp /home/user/Documents/python/entropy/miopt.py ./entropy
cp /home/user/Documents/python/entropy/miprint.py ./entropy
cp /home/user/Documents/python/entropy/run-logs.py ./entropy
cp /home/user/Documents/python/modules/disk/*.py ./modules/disk
cp /home/user/Documents/python/modules/general/*.py ./modules/general
cp /home/user/Documents/python/modules/probability/*.py ./modules/probability
cp /home/user/Dropbox/data/outputs/obj-meta-vars/*.obj ./obj-meta-vars
tar -czf enropy/* binary-files/* modules/* nltk_data/* obj-meta-vars/*
Complete

我想与检查现有文件夹有关的依赖关系肯定有问题。

谢谢。

2 个答案:

答案 0 :(得分:2)

问题在于您的复制规则具有以下形式:

$(ENTDIR)/mifunction.py: $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/mifunction.py ./$(ENTDIR)

请注意,目标目录是先决条件。如果目录的时间戳比目标的时间戳晚,则Make将认为目标已过期,并且操作系统会在添加文件(或删除文件)时更新目录的时间戳。由于此Makefile将其他文件复制到该目录,因此下次运行Make时,该目标似乎已过时。

有多种解决方法。最简单的方法是通过添加管道('|')将先决条件更改为order-only prerequisite

$(ENTDIR)/mifunction.py: | $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/mifunction.py ./$(ENTDIR)

一旦确认此方法有效,就可以进行其他改进。您可能考虑使用原始文件作为先决条件:

$(ENTDIR)/mifunction.py: /home/user/Documents/python/$(ENTDIR)/mifunction.py | $(ENTDIR)
    cp /home/user/Documents/python/$(ENTDIR)/mifunction.py ./$(ENTDIR)

在您介绍automatic variables之前,这看起来很笨拙:

$(ENTDIR)/mifunction.py: /home/user/Documents/python/$(ENTDIR)/mifunction.py | $(ENTDIR)
    cp $< $@

是否执行此操作,可以引入另一个变量:

PYTHON_DIR := /home/user/Documents/python

这将消除很多冗余。

进一步的改进是可能的,但是现在可能已经足够了。

答案 1 :(得分:1)

尝试回答问题的“避免-避免”部分:首先,使用自动变量来引用规则内的目标或先决条件,例如

$(WEST)/west.obj: $(WEST)
    cp /home/user/Documents/python/$@ $<

然后,该规则在很多地方看起来应该相同,这可以进行下一个更改-将相同的规则定义为变量:

COPY = cp /home/user/Documents/python/$@ $<

$(WEST)/west.obj: $(WEST)
    $(COPY)

接下来,使用变量作为路径,例如

PYTHON_SOURCE_PATH = /home/user/Documents/python/

,并在需要此规则的所有规则中使用此变量(或如前所示的COPY变量)。您应该仅通过编辑设置变量的特定行就可以更改此路径。接下来,收集可能也在变量中创建的目录。然后,许多规则可以用一个规则代替:

DIRECTORIES = $(NORTH) $(SOUTH) # ... the others

$(DIRECTORIES):
    mkdir -p $@