【问题标题】:Any interesting uses of Makefiles to share?Makefile 有什么有趣的用途可以分享吗?
【发布时间】:2010-09-28 13:21:41
【问题描述】:

“make”不仅对构建您的编程项目有用,而且在其他领域似乎没有得到充分利用。

例如,可以将许多 shell 脚本重写为 Makefile 以允许独立部分并行运行(使用“make -jXX”)以保持所有 CPU 内核繁忙,并显式声明依赖项作为额外的好处,以防万一你会考虑在你的 shell 脚本中重新排序一些有副作用的任务。

你有什么有趣的故事可以分享吗?您是否使用其他一些实用程序作为廉价的作业调度程序?

【问题讨论】:

    标签: bash scripting makefile gnu-make


    【解决方案1】:

    Make 的并行性对于 shell 脚本特别方便。假设您想获得一整套主机的“正常运行时间”(或基本上执行任何缓慢的操作)。您可以循环执行:

    cat hosts | while read host; do echo "$host: $(ssh $host uptime)"; done
    

    这可行,但速度很慢。您可以通过生成子shell 来并行化:

    cat hosts | while read host; do (echo "$host: $(ssh $host uptime)")&; done
    

    但是现在您无法控制生成多少线程,并且 CTRL-C 不会完全中断所有线程。

    这是 Make 解决方案:将其保存到文件(例如 showuptimes)并标记为可执行文件:

    #!/usr/bin/make -f
    
    hosts:=$(shell cat)
    all: ${hosts}
    
    ${hosts} %:
            @echo "$@: `ssh $@ uptime`"
    
    .PHONY: ${hosts} all
    

    现在运行cat hosts | ./showuptimes 将一一打印正常运行时间。 cat hosts | ./showuptimes -j 将并行运行它们。调用者可以直接控制并行化程度 (-j),或者可以通过系统负载间接指定它 (-l)。

    【讨论】:

    • Nitpick: "./showuptimes
    【解决方案2】:

    除了在编程中的明显用途外,我还看到 Makefile 用于在服务器上执行重复性任务以管理系统设置,例如用户/组创建、包升级/更新以及将配置文件复制到位。我还看到(并使用过)rake 在基于 Ruby 的环境中执行此操作。

    我听说过的最复杂的例子是ISConf,一个配置管理工具。我是从Puppet 的作者 Luke Kanies 在his blog 上听说的。

    【讨论】:

      【解决方案3】:

      根据 'make' 的种类,您可以使用可执行的 makefile 与 shell 脚本来处理任务的依赖关系.. 即在一个 init 脚本需要启动 10 个服务的场景中......一个接一个(即服务二需要服务一在启动之前启动并处于活动状态),它可以通过makefile轻松完成。

      很多 GNU/Linux 打包器都使用这个,例如 debian/rules 和其他。所以是的,如果操作正确,make 在启动程序和构建程序方面同样出色。

      问题是,并不是每个人都安装了构建工具链。所以 shell 脚本或批处理文件仍然是可移植的(因此是“正确的”)方法。

      【讨论】:

        【解决方案4】:

        这可能意味着我的想象力不足,但是很难在makefile中获得足够的灵活性来进行这种使用。实现它的“明显”方法是在“make”命令行上指定宏值。

        make -f script.mk MACRO="list of files on which to operate"
        

        这比一个简单的 shell 脚本更冗长 - 而且你失去了使用 shell 文件名扩展的简单能力。解决方法是:

        make -f script.mk MACRO="$(echo *[io]*)"
        

        我会提出这个关于 Why not use #!/bin/make at the top of makefiles 的 SO 问题,作为(可执行)makefile 的一种奇怪用途,但目标不是做不寻常的事情(只是无聊的旧软件构建);只是为了对make 使用不寻常的调用机制。

        使用该技术,您可以将调用简化为:

        script.mk MACRO="$(echo *[io]*)"
        

        这仍然比:

        script *[io]*
        

        我想script 可以写成调用make。这一切都取决于。我不相信有足够的里程可以从中获得。 YMMV。

        【讨论】:

        • GNU Make 支持 $(MAKECMDGOALS),我过去曾用它来创建 Makefile 脚本,它可以直接在命令行上接受随机垃圾,而无需经过这些环节。
        • 另见 jturner 使用 $(shell cat) 从标准输入读取的解决方案。
        【解决方案5】:

        Make 也可以用作同步实用程序。例如:

        #!/usr/bin/make -f
        
        FILES = *.html *.js *.css images/*.jpg subpage/*.html
        LAST_SYNC = .last_sync
        SCP = scp webserver.com:/home/john/public_html
        
        .PHONY: sync
        
        sync : $(LAST_SYNC)
        
        $(LAST_SYNC) : $(FILES)
            $(SCP) $?
            touch $(LAST_SYNC)
        

        这个 Makefile 创建了一个空文件.last_sync,用于记录我们上一次将本地存储库与远程存储库同步的时​​间。每次运行此脚本时,Make 都会检查 FILES 中列出的任何文件自上次运行同步以来是否已被修改,将它们复制到服务器,然后更新 .last_sync 上的时间戳。关键是自动变量$?,它包含比规则目标更新的所有先决条件的列表。

        【讨论】:

          【解决方案6】:

          我的工作使用了一个奇怪的东西:依赖项不存在,所以它总是重建一切。

          还不如使用批处理文件。

          【讨论】:

          【解决方案7】:

          make 也用于驱动进程........我最近才知道这个, 不仅仅是个人安装或管理构建,而是整个过程。以前我认为 make 仅用于编译项目,但只要有可能需要执行的依赖项或活动链,make 就可以在那里使用......我最近看到了一个管理代码直到交付/部署的流程的所有内容,包括数据处理更新(24 小时 +).... 好东西 :)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-09-25
            • 1970-01-01
            • 2012-11-29
            • 1970-01-01
            • 2011-01-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多