【问题标题】:Override command for make from outside从外部覆盖命令
【发布时间】:2018-07-07 12:46:54
【问题描述】:

我有几个包含文件 stamp1.txt 和 stamp0.txt 的目录,我想要覆盖 cat 命令。例如,我需要它来禁止将“stamp1”文件归档到库中。

所以我编写了一个名为“realname”的小过滤程序和 bash 脚本来覆盖原来的 cat 命令。

function cat() { 

    local e=""

    for s in $@
    do
        if realname $s; then
            e=$e" "$s;
        fi
    done

    command cat $e;
}

所以命令:

cat dir1/stamp1.txt dir2/stamp0.txt

将转换为

cat dir2/stamp0.txt

这个例子很好用

ar cruv some_lib.a `cat dir1/stamp1.txt dir2/stamp0.txt`

但是当我运行一些 makefile 来构建一些软件时 - 在这个过程中使用原始 cat 也没有被覆盖。

如何在不更改 makefile 的情况下覆盖 cat 或任何其他命令以使其在 make 过程中工作(makefile 是 3rdparty 软件,我不希望每次需要升级时都对其进行修补) ?

【问题讨论】:

  • 移动或重命名stamp1.txt不是更容易吗?
  • 在我看来,步骤(1)确保使用宏CAT = cat并在命令行中引用它(所以ar cruv some_lib.a cat dir1/stamp1.txt dir2/stamp0.txt`变成${AR} ${ARFLAGS} ${LIBNAME} `${CAT} ${STAMP1} ${STAMP2}` ) 和 (2) 在 Make 命令行上调整 STAMP1=CAT=your-shell-script(脚本,不是函数!)。如果一切都是宏,您可以根据需要调整结果——在非常广泛的范围内。如果硬连线命令名称或选项标志,则会失去一些灵活性。不管眼前的问题如何,广泛使用宏是个好主意。
  • 其他人的 makefile 存在问题——它们并不总是用最大的宏编写。如果他们忽略了该建议(他们可能会这样做),那么请考虑sed 's/cat dir1/mycat dir1/' makefile > makefile.new; make -f makefile.new; rm -f makefile.new 的优点,您可以在其中即时编辑生成文件。您可能需要比我在sed 命令中概述的更敏感的搜索条件。

标签: bash makefile overriding cat unix-ar


【解决方案1】:

你不能用 shell 函数来做到这一点,因为 shell 函数只存在于本地 shell 中。它不会传递给像make 这样的程序。另外,GNU make 默认总是调用/bin/sh,而不是/bin/bash,而且你上面的shell函数是用bash语法编写的,所以把它放在你的~/.bashrc中不会有任何影响。

你可以跑:

$ make SHELL=/bin/bash

并将该 shell 函数添加到您的 ~/.bashrc 中,这可能会起作用。

您唯一可以做的另一件事(假设您的第三方 makefile 直接调用 cat 并且不使用像 $(CAT) 这样的变量)是创建一个 cat shell 脚本(不是函数)和调用 make 时,将其放在 PATH 之前的 /bin/usr/bin 上。比如:

$ mkdir tmp
$ vi tmp/cat
    ...add commands...
$ chmod 755 tmp/cat
$ PATH=$(pwd)/tmp:$PATH make ...

当然,当你这样做时,你不能在你的脚本中使用command cat ...,你必须使用像/bin/cat ...这样的完全限定路径

【讨论】:

    【解决方案2】:

    短版:你不能(而且你可能不想这样做)。

    加长版:您已经定义了一个 shell 函数。实际上,您甚至可以将该 shell 函数导出到环境 export -f cat 中。但除非 Makefile 说的是 bash -c cat ... 而不仅仅是 cat(或其他相同效果的引用),否则它不会给你想要的行为。

    如果你真的坚持...并且 Makefile 没有使用硬编码路径(例如/bin/cat)。你可以写你自己的猫,把它放在某个地方,然后把这个位置放在cat的其他可能命中之前(把它放在前面)。

    还有一些机会(查看 make 文件)它使用变量(例如 CAT)来知道要调用什么,因此如果是这种情况,您可以提供自己的定义。

    无论如何。我不鼓励您使用此类解决方法,因为这样做会混淆机器的实际行为。这里声明了一些东西......环境中的其他东西赋予了它不同的含义。这是一个非常常见的错误来源,并最终导致不明显(更难解决)的错误。


    功能位的示例/说明。我有一个 Makefile:

    all:
        @echo foo
    

    并定义和导出一个“覆盖”回声的函数。 echo() { /bin/echo "$@" bar; } ; export -f echo。我运行 make 并获取:

    $ make
    foo
    

    因为 make 只是在 PATH 中查找 echo(尝试到 exec 并且一旦找到它,它就会运行它)。如果我将其更改为中间有 bash 步骤,则导出的函数会启动,但是...这是在 make 中使用命令的常用方法,您必须编辑您不想要的 Makefile:

    all:
        @bash -c 'echo foo'
    

    这会产生你想要的结果:

    $ make
    foo bar
    

    我提到的另一个选项。我已经将该函数的行为放入脚本/tmp/bin/echo 阅读:

    #!/bin/bash
    /bin/echo "$@" bar
    

    我已经修改了PATH env var export PATH=/tmp/bin:$PATH。现在即使使用 Makefile 的第一种形式:

    all:
        @echo foo
    

    我明白了:

    $ make
    foo bar
    

    但如果给出的 Makefile 改为 /bin/echo,我就没有这样的运气了。您仍然可以更改二进制文件...或通过强制共享库预加载来更改其行为...但听起来很极端,并充分揭示了为什么这确实可能不是采用它的最佳方向。

    【讨论】:

      猜你喜欢
      • 2012-10-30
      • 2016-05-05
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 2020-03-04
      • 1970-01-01
      相关资源
      最近更新 更多