我遇到的情况是需要远程运行一些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
我想与检查现有文件夹有关的依赖关系肯定有问题。
谢谢。
答案 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 $@