在 Makefile 中生成并检查下载文件校验和
Generate and check download file checksum in Makefile
作为我的 makefile
的一部分,我需要下载并构建 ZLib。但是我想确保当我下载 ZLib 时,通过将下载的 .tar.gz 的 sha256 与已知的正确 sha256 值进行比较来确保它是正确的。这需要在多个平台上工作。
到目前为止,我有类似下面的内容,但是当我将它与 ZLIB_SHA256
进行比较时,ZLIB_SHA256_ACTUAL
的值似乎总是空白,所以我的 makefile 总是以错误退出,因为校验和不一样。我是 Makefile 的新手,有人可以告诉我我做错了什么吗?
ZLIB_VER = 1.2.11
ZLIB_SHA256 = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
SHA256_CMD = sha256sum
ifeq ($(PLATFORM), OS_MACOSX)
SHA256_CMD = openssl sha256 -r
endif
ifeq ($(PLATFORM), OS_SOLARIS)
SHA256_CMD = digest -a sha256
endif
libz.a:
-rm -rf zlib-$(ZLIB_VER)
curl -O -L http://zlib.net/zlib-$(ZLIB_VER).tar.gz
ZLIB_SHA256_ACTUAL = $(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz
ifneq ($(ZLIB_SHA256), $(ZLIB_SHA256_ACTUAL))
$(error zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected="$(ZLIB_SHA256)" actual="$(ZLIB_SHA256_ACTUAL)")
endif
tar xvzf zlib-$(ZLIB_VER).tar.gz
cd zlib-$(ZLIB_VER) && CFLAGS='-fPIC' ./configure --static && make
cp zlib-$(ZLIB_VER)/libz.a .
一个 makefile 在一个文件中包含两种不同的编程语言。大多数文件使用 makefile 语法,make 可以理解和解析。但是规则的食谱使用 shell 语法,make 不会尝试解释:它只是将食谱的内容传递给 shell 来解释。
配方是 makefile 的一部分,在目标定义之后用制表符缩进。因此,在上面的示例中,目标定义是 libz.a:
并且之后所有用 TAB 缩进的行都是配方行。它们由 make
.
传递给 shell,而不是 运行
食谱是一行;您不能将配方行与 makefile 行穿插在一起。一旦 make 看到第一个 non-recipe 行,这就是配方的结尾,make 开始将剩余的行视为 makefile 行。
让我们看看你的规则:
libz.a:
-rm -rf zlib-$(ZLIB_VER)
curl -O -L http://zlib.net/zlib-$(ZLIB_VER).tar.gz
好的,这很好:您已经创建了一个目标 libz.a
并在您的配方中提供了两个有效的 shell 命令命令行。
ZLIB_SHA256_ACTUAL = $(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz
好的,现在你有问题了;这是一个 make 变量赋值,而不是 shell 命令,但是因为你已经用 TAB 缩进了它,所以 make 不会解释它:make 只会将它传递给 shell。那不是有效的 shell 命令(在 shell 中,变量赋值不能在等号两边有空格);这是试图 运行 一个字面上命名为 ZLIB_SHA256_ACTUAL
的程序,并将参数 =
和 SHA256_CMD
变量的扩展传递给它。即使这被识别为 make 赋值,它也不会执行您想要的操作,因为它只会将变量的值设置为字符串 openssl sha256 -r zlib-1.2.11.tar.gz
: you want to 运行 that command and set the variable到输出。
然后下一行:
ifneq ($(ZLIB_SHA256), $(ZLIB_SHA256_ACTUAL))
$(error zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected="$(ZLIB_SHA256)" actual="$(ZLIB_SHA256_ACTUAL)")
endif
同样,这是错误的,因为这些是 make 命令,但您已将它们放入配方中,这意味着它们将被传递给 shell,但是shell 对他们一无所知。
但是,它们从来没有机会被传递给 shell,因为 make 在将配方发送给 shell 之前对配方所做的一件事是展开所有 make 变量和函数.因此,当 make 扩展它时 运行 是 error
函数,它立即失败并且 make 永远没有机会尝试 运行 配方。
这是 make 的棘手部分。也许我只是把你和上面的所有东西搞混了。
简短的回答是:您必须使用 shell 命令来执行配方中的操作。你不能使用 make 命令(如 ifeq
等),如果你想在配方中设置变量,它们必须是 shell 个变量,而不是 生成 个变量。
所以,你想要这样的东西,它使用 shell 语法而不是 make 变量赋值和测试语法。
EDIT 请注意,您的 SHA 生成命令不仅会打印 SHA,还会打印文件名,因此您不能将它们作为字符串进行比较:它们会永远不一样。您需要做一些更有趣的事情;有很多方法可以解决这个问题。这里我决定用case
来做比较:
libz.a:
-rm -rf zlib-$(ZLIB_VER)
curl -O -L http://zlib.net/zlib-$(ZLIB_VER).tar.gz
ZLIB_SHA256_ACTUAL=`$(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz`; \
case "$$ZLIB_SHA256_ACTUAL " in \
($(ZLIB_SHA256)\ *) : ok ;; \
(*) echo zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected=\"$(ZLIB_SHA256)\" actual=\"$$ZLIB_SHA256_ACTUAL\"; \
exit 1 ;; \
esac
tar xvzf zlib-$(ZLIB_VER).tar.gz
cd zlib-$(ZLIB_VER) && CFLAGS='-fPIC' ./configure --static && $(MAKE)
cp zlib-$(ZLIB_VER)/libz.a .
请注意,配方中的每个逻辑行都会传递给 shell 的一个新实例,因此如果您想设置一个 shell 变量并测试其值,您必须组合物理行使用 backslash/newline 语法合并为一个逻辑行。
此外,当 运行在食谱中使用 sub-make 时,您应该始终使用变量 $(MAKE)
而永远不要只使用 make
.
作为我的 makefile
的一部分,我需要下载并构建 ZLib。但是我想确保当我下载 ZLib 时,通过将下载的 .tar.gz 的 sha256 与已知的正确 sha256 值进行比较来确保它是正确的。这需要在多个平台上工作。
到目前为止,我有类似下面的内容,但是当我将它与 ZLIB_SHA256
进行比较时,ZLIB_SHA256_ACTUAL
的值似乎总是空白,所以我的 makefile 总是以错误退出,因为校验和不一样。我是 Makefile 的新手,有人可以告诉我我做错了什么吗?
ZLIB_VER = 1.2.11
ZLIB_SHA256 = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
SHA256_CMD = sha256sum
ifeq ($(PLATFORM), OS_MACOSX)
SHA256_CMD = openssl sha256 -r
endif
ifeq ($(PLATFORM), OS_SOLARIS)
SHA256_CMD = digest -a sha256
endif
libz.a:
-rm -rf zlib-$(ZLIB_VER)
curl -O -L http://zlib.net/zlib-$(ZLIB_VER).tar.gz
ZLIB_SHA256_ACTUAL = $(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz
ifneq ($(ZLIB_SHA256), $(ZLIB_SHA256_ACTUAL))
$(error zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected="$(ZLIB_SHA256)" actual="$(ZLIB_SHA256_ACTUAL)")
endif
tar xvzf zlib-$(ZLIB_VER).tar.gz
cd zlib-$(ZLIB_VER) && CFLAGS='-fPIC' ./configure --static && make
cp zlib-$(ZLIB_VER)/libz.a .
一个 makefile 在一个文件中包含两种不同的编程语言。大多数文件使用 makefile 语法,make 可以理解和解析。但是规则的食谱使用 shell 语法,make 不会尝试解释:它只是将食谱的内容传递给 shell 来解释。
配方是 makefile 的一部分,在目标定义之后用制表符缩进。因此,在上面的示例中,目标定义是 libz.a:
并且之后所有用 TAB 缩进的行都是配方行。它们由 make
.
食谱是一行;您不能将配方行与 makefile 行穿插在一起。一旦 make 看到第一个 non-recipe 行,这就是配方的结尾,make 开始将剩余的行视为 makefile 行。
让我们看看你的规则:
libz.a:
-rm -rf zlib-$(ZLIB_VER)
curl -O -L http://zlib.net/zlib-$(ZLIB_VER).tar.gz
好的,这很好:您已经创建了一个目标 libz.a
并在您的配方中提供了两个有效的 shell 命令命令行。
ZLIB_SHA256_ACTUAL = $(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz
好的,现在你有问题了;这是一个 make 变量赋值,而不是 shell 命令,但是因为你已经用 TAB 缩进了它,所以 make 不会解释它:make 只会将它传递给 shell。那不是有效的 shell 命令(在 shell 中,变量赋值不能在等号两边有空格);这是试图 运行 一个字面上命名为 ZLIB_SHA256_ACTUAL
的程序,并将参数 =
和 SHA256_CMD
变量的扩展传递给它。即使这被识别为 make 赋值,它也不会执行您想要的操作,因为它只会将变量的值设置为字符串 openssl sha256 -r zlib-1.2.11.tar.gz
: you want to 运行 that command and set the variable到输出。
然后下一行:
ifneq ($(ZLIB_SHA256), $(ZLIB_SHA256_ACTUAL))
$(error zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected="$(ZLIB_SHA256)" actual="$(ZLIB_SHA256_ACTUAL)")
endif
同样,这是错误的,因为这些是 make 命令,但您已将它们放入配方中,这意味着它们将被传递给 shell,但是shell 对他们一无所知。
但是,它们从来没有机会被传递给 shell,因为 make 在将配方发送给 shell 之前对配方所做的一件事是展开所有 make 变量和函数.因此,当 make 扩展它时 运行 是 error
函数,它立即失败并且 make 永远没有机会尝试 运行 配方。
这是 make 的棘手部分。也许我只是把你和上面的所有东西搞混了。
简短的回答是:您必须使用 shell 命令来执行配方中的操作。你不能使用 make 命令(如 ifeq
等),如果你想在配方中设置变量,它们必须是 shell 个变量,而不是 生成 个变量。
所以,你想要这样的东西,它使用 shell 语法而不是 make 变量赋值和测试语法。
EDIT 请注意,您的 SHA 生成命令不仅会打印 SHA,还会打印文件名,因此您不能将它们作为字符串进行比较:它们会永远不一样。您需要做一些更有趣的事情;有很多方法可以解决这个问题。这里我决定用case
来做比较:
libz.a:
-rm -rf zlib-$(ZLIB_VER)
curl -O -L http://zlib.net/zlib-$(ZLIB_VER).tar.gz
ZLIB_SHA256_ACTUAL=`$(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz`; \
case "$$ZLIB_SHA256_ACTUAL " in \
($(ZLIB_SHA256)\ *) : ok ;; \
(*) echo zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected=\"$(ZLIB_SHA256)\" actual=\"$$ZLIB_SHA256_ACTUAL\"; \
exit 1 ;; \
esac
tar xvzf zlib-$(ZLIB_VER).tar.gz
cd zlib-$(ZLIB_VER) && CFLAGS='-fPIC' ./configure --static && $(MAKE)
cp zlib-$(ZLIB_VER)/libz.a .
请注意,配方中的每个逻辑行都会传递给 shell 的一个新实例,因此如果您想设置一个 shell 变量并测试其值,您必须组合物理行使用 backslash/newline 语法合并为一个逻辑行。
此外,当 运行在食谱中使用 sub-make 时,您应该始终使用变量 $(MAKE)
而永远不要只使用 make
.