【问题标题】:Make does not follow symbolic links to find filesMake 不遵循符号链接来查找文件
【发布时间】:2020-05-08 05:30:15
【问题描述】:

当我从 tar 球中提取文件以创建文件列表时,make 不遵循符号链接,并为列表中指定的每个文件继续提取相同的 tar 球。例如,我在 linux 中使用以下命令创建了 2 个 tar 球:

design1 是一个目录,其中包含指向具有 c 设计文件的另一个目录的链接

% mkdir design1
% mkdir c_files
% cd c_files/
% touch a.c b.c c.c d.c e.c f.c
% cd ../design1/
% ln -s ../c_files/ .
% cd ..
% gtar zcvf design1.tgz design1/

design2 与 design1 相同,只是 c_files 是目录而不是链接

% mkdir design2
% 
% cp -rp c_files design2
% gtar zcvf design2.tgz design2/

现在有 2 个压缩 tar 文件 design1.tgz 和 design2.tgz 并且 design1 和 design2 目录被删除

% \rm -rf design1 design2

这是我的 Makefile: ----------------开始 Makefile --------------------------------

DESIGN_EXTRACT_DIR := .
DESIGN_TOP1 := c_proj1
FILE_LIST1 := $(strip $(DESIGN_TOP1)).f


DESIGN_TAR_FILE1 := design1.tgz
DESIGN_RELEASE_DIR1 := $(DESIGN_EXTRACT_DIR)/design1

DESIGN_FILES1 =\
$(DESIGN_RELEASE_DIR1)/c_files/a.c   \
$(DESIGN_RELEASE_DIR1)/c_files/b.c   \
$(DESIGN_RELEASE_DIR1)/c_files/c.c   \
$(DESIGN_RELEASE_DIR1)/c_files/d.c   \
$(DESIGN_RELEASE_DIR1)/c_files/e.c   \
$(DESIGN_RELEASE_DIR1)/c_files/f.c   \


IP_EXTRACT1: $(DESIGN_FILES1) 

$(DESIGN_FILES1): $(DESIGN_TAR_FILE1)   
    gtar zxvfmhC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR) 

$(FILE_LIST1): $(DESIGN_FILES1) 
    @( rm -f $(FILE_LIST1) )
    @( touch $(FILE_LIST1) )
    @$(foreach file, $(DESIGN_FILES1), `echo $(file) >> $(FILE_LIST1)`)


FL1:    $(FILE_LIST1)

DESIGN_TOP2 := c_proj2
FILE_LIST2 := $(strip $(DESIGN_TOP2)).f


DESIGN_TAR_FILE2 := design2.tgz
DESIGN_RELEASE_DIR2 := $(DESIGN_EXTRACT_DIR)/design2

DESIGN_FILES2 =\
$(DESIGN_RELEASE_DIR2)/c_files/a.c   \
$(DESIGN_RELEASE_DIR2)/c_files/b.c   \
$(DESIGN_RELEASE_DIR2)/c_files/c.c   \
$(DESIGN_RELEASE_DIR2)/c_files/d.c   \
$(DESIGN_RELEASE_DIR2)/c_files/e.c   \
$(DESIGN_RELEASE_DIR2)/c_files/f.c   \


IP_EXTRACT2: $(DESIGN_FILES2) 

$(DESIGN_FILES2): $(DESIGN_TAR_FILE2)   
    gtar zxvfmhC $(DESIGN_TAR_FILE2) $(DESIGN_EXTRACT_DIR) 

$(FILE_LIST2): $(DESIGN_FILES2) 
    @( rm -f $(FILE_LIST2) )
    @( touch $(FILE_LIST2) )
    @$(foreach file, $(DESIGN_FILES2), `echo $(file) >> $(FILE_LIST2)`)


FL2:    $(FILE_LIST2)

clean: 
    @( rm -rf $(FILE_LIST1)* $(FILE_LIST2)* )

----------------结束 Makefile----------------------

现在,当我运行 make 创建文件列表时,我使用命令 make FL1 和 make FL2。在 FL1 的情况下,gtar 的迭代次数与我拥有的文件一样多,但在 FL2 中没有这样做。此处唯一的区别是 FL1 在 design1 中名为 c_files 的链接上运行,而 FL2 将 c_files 作为目录进行迭代。 这是我看到的:

% make FL1
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files


%make FL2
%

问题1: FL1 创建 c_proj1.f 和 FL2 创建 c_proj2.f 但 FL2 不像 FL1 那样迭代,我不知道如何防止这种迭代,特别是因为我可能有包含数百个文件的大型 tar 球。

问题2: 当 DESIGN_FILES1 由于文件数量而成为长列表时,由于变量太长,我收到以下错误: make: execvp: /bin/sh: 参数列表太长

有没有办法检查变量的大小,并可能写入文件并一次处理变量,这样每次迭代的 DESIGN_FILES 不会太长。或者有没有更好的方法来做到这一点。

谢谢

尼尔

【问题讨论】:

    标签: makefile symlink


    【解决方案1】:

    对我来说,无论是否有符号链接,它的工作原理都是一样的(迭代一次)。但从内容上看,您似乎只对生成文件列表感兴趣,因此文件存在并不是真正需要的。如果省略依赖,可能会生成文件列表,甚至不需要提取文件。

    对于实际的文件列表写入过大的命令行错误来自这样一个事实,即生成的命令是带有多个子shell调用的单行,这对于命令行来说确实可能太长了:

    $ make FL1 --trace
    ...
    Makefile:24: update target 'c_proj1.f' due to: design1/c_files/a.c design1/c_files/b.c design1/c_files/c.c design1/c_files/d.c design1/c_files/e.c design1/c_files/f.c
    ( rm -f c_proj1.f )
    ( touch c_proj1.f )
    `echo ./design1/c_files/a.c >> c_proj1.f`  `echo ./design1/c_files/b.c >> c_proj1.f`  `echo ./design1/c_files/c.c >> c_proj1.f`  `echo ./design1/c_files/d.c >> c_proj1.f`  `echo ./design1/c_files/e.c >> c_proj1.f`  `echo ./design1/c_files/f.c >> c_proj1.f`
    

    这部分可以用$(file)函数解决(如果你碰巧使用GNU make 4.1+):

    .PHONY: $(FILE_LIST1)
    $(FILE_LIST1):
            $(file >$@)
            $(foreach file,$(DESIGN_FILES1),$(file >>$@,$(file)))
    

    如果使用较旧的 make,这可以通过常规命令完成,您只需在每个 echo 后生成一个换行符,使其作为单独的命令工作。唯一棘手的部分是它必须作为特制变量来完成:

    # Note double empty lines below
    define newline
    
    
    endef
    
    .PHONY: $(FILE_LIST2)
    $(FILE_LIST2):
            rm -f $@
            $(foreach file,$(DESIGN_FILES2),echo $(file) >> $@$(newline))
    

    结果现在在单独的 shell 调用中生成,这应该避免命令长度限制:

    $ make FL2
    rm -f c_proj2.f
    echo ./design2/c_files/a.c >> c_proj2.f
    echo ./design2/c_files/b.c >> c_proj2.f
    echo ./design2/c_files/c.c >> c_proj2.f
    echo ./design2/c_files/d.c >> c_proj2.f
    echo ./design2/c_files/e.c >> c_proj2.f
    echo ./design2/c_files/f.c >> c_proj2.f
    

    编辑:

    我能够重现您的多次提取迭代。您的 tgz 文件实际上并不包含您声称要提取的文件,因此当尝试提取第一个文件并且提取下一个文件(也没有)时,这些文件不存在。 tar 输出也建议这样做,它说:

    design1/
    design1/c_files
    

    代替:

    design1/
    design1/c_files
    design1/c_files/a.c
    design1/c_files/b.c
    design1/c_files/c.c
    design1/c_files/d.c
    design1/c_files/e.c
    design1/c_files/f.c
    

    您的tgz 只包含一个目录符号链接,它只提取一个符号链接。如果目标位置不存在目标文件,它将尝试为每个文件重新提取。

    EDIT2:

    当实际文件不包含在tgz 文件中,但可以通过符号链接获得时,它们有可能比tgz 文件本身更早。在这种情况下make 通过符号链接检查文件时间戳并发现它需要重新制作 - 但文件实际上并未重新制作(因为它不包含在tgz 中)。对每个文件都进行此检查,因此对于每个文件都提取存档:

    $ make FL1 -d
    ...
         Finished prerequisites of target file 'design1/c_files/a.c'.
         Prerequisite 'design1.tgz' is newer than target 'design1/c_files/a.c'.
        Must remake target 'design1/c_files/a.c'.
    tar zxvfmhC design1.tgz .
    Putting child 0x7fffe11ae730 (design1/c_files/a.c) PID 6286 on the chain.
    Live child 0x7fffe11ae730 (design1/c_files/a.c) PID 6286
    design1/
    design1/c_files
    Reaping winning child 0x7fffe11ae730 PID 6286
    Removing child 0x7fffe11ae730 PID 6286 from chain.
        Successfully remade target file 'design1/c_files/a.c'.
        Considering target file 'design1/c_files/b.c'.
          Pruning file 'design1.tgz'.
         Finished prerequisites of target file 'design1/c_files/b.c'.
         Prerequisite 'design1.tgz' is newer than target 'design1/c_files/b.c'.
        Must remake target 'design1/c_files/b.c'.
    tar zxvfmhC design1.tgz .
    ...
    

    通常以这种方式提取存档无论如何都不可靠(图像与-j并行运行),因此最好使用group target rule明确指出该规则同时生成所有文件时间:

    $(DESIGN_FILES1) &: $(DESIGN_TAR_FILE1)
            tar zxvfmhC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR)
    

    然而,这是 GNU make 4.3 中引入的一项新功能,因此要使其与以前的版本一起使用,我们可以使用仅用于同步的虚假目标,例如:

    $(DESIGN_FILES1): extract-$(DESIGN_TAR_FILE1)
    
    .PHONY: extract-$(DESIGN_TAR_FILE1)
    extract-$(DESIGN_TAR_FILE1):
            tar zxvfmhC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR)
    

    输出:

    $ make FL1
    tar zxvfmhC design1.tgz .
    design1/
    design1/c_files
    

    请注意,存档现在只提取一次。

    【讨论】:

    • 感谢您的回复。在这个 sn-p 中,我正在生成一个文件列表,但我使用文件列表进行编译,所以我需要执行 tar 并提取文件,并且文件必须退出,否则编译将失败。
    【解决方案2】:

    我听从了您的建议并更改了依赖项,它解决了 tar 问题。 make 中的文件函数解析了变量的长度,但由于它我有 2 个不希望的效果。我在这里又添加了一件东西,我无法解释这种行为:

    在 Linux 上:

      % mkdir -p design3/c_files
      % cd design3/c_files
      % touch x.c y.c z.c
      % cd ../..
      % ls ./design3/c_files/*.c >  design3/c_proj3.f
    

    这是我对 Makefile 所做的:

    DIR_LIST := design3
    
    IP_EXTRACT1: $(DESIGN_TAR_FILE1)   
        gtar zxvfmC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR) 
    
    $(DESIGN_FILES1): 
        $(MAKE) IP_EXTRACT1
    
    $(FILE_LIST1):  $(DESIGN_FILES1) 
        $(file > $(FILE_LIST1))
        @$(if $(strip $(DIR_LIST)), cat $(foreach dir, $(DIR_LIST), $(wildcard $(dir)/*.f)) >> $(FILE_LIST1))
        @$(foreach file,$(DESIGN_FILES1),$(file >>$(FILE_LIST1),$(file)))
    

    这解决了 tar 问题,但现在我添加了 DIR_LIST,我想将每个目录中的文件列表添加到文件列表中。它做了正确的事,但有一些不良影响:

    1) 我希望 design3/c_proj3.f 的内容在顶部,但它出现在最后。

    %make FL1
    %more c_proj1.f
    ./design1/c_files/a.c
    ./design1/c_files/b.c
    ./design1/c_files/c.c
    ./design1/c_files/d.c
    ./design1/c_files/e.c
    ./design1/c_files/f.c
    ./design3/c_files/x.c
    ./design3/c_files/y.c
    ./design3/c_files/z.c
    

    我希望 x、y、z 位于顶部,因为存在顺序依赖性,但它位于底部。此外,如果我在删除 c_proj1.f 之后确实使 FL1 --dry-run 文件 a 到 f 进入其中但不是 x,y,z 因为这是来自 cat shell 命令。我宁愿不创建文件。有没有办法解决这个问题?这是一个部分解决方案,所以我不确定这是否需要回到问题中。

    【讨论】:

      猜你喜欢
      • 2015-11-06
      • 2012-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-17
      • 1970-01-01
      相关资源
      最近更新 更多