在定义的函数中使用 awk 命令时无法获得正确的参数
can't get correct arguments when use awk command in a defined function
项目中有一个version.h文件,像这样:
#ifndef _VERSION_H_
#define _VERSION_H_
#define PROJNAME "Uranium"
#define VERSION "1.0.1"
#endif
而且我想在使用make编译项目时打印项目名称和版本。
所以我添加了以下 makefile:
PROJNAME_KEYWORD = "PROJNAME"
VERSION_KEYWORD = "VERSION"
define GetPropValue
$(shell \
awk '{ \
split($[=11=], words, " "); \
for (i in words) { \
if (index(words[i], $$(1)) != 0) { \
word = words[i + 1]; \
gsub("\"", "", word); \
print word; \
break; \
} \
} \
}' version.h \
)
endef
ifndef PROJNAME
PROJNAME = $(call GetPropValue, $(PROJNAME_KEYWORD))
endif
ifndef VERSION
VERSION = $(call GetPropValue, $(VERSION_KEYWORD))
endif
预计会有这个:
PROJNAME = Uranium
VERSION = 1.0.1
但实际上我得到了这个,
PROJNAME=_VERSION_H_ _VERSION_H_ PROJNAME VERSION
VERSION=_VERSION_H_ _VERSION_H_ PROJNAME VERSION
经过一些调试过程,我在
中找到了$$(1)
if (index(words[i], $$(1)) != 0) {
行不正确,
当我用 "PROJNAME" 替换 $$(1) 时,
我可以得到正确的结果,
PROJNAME = Uranium
$$(1) 应该是参数,比如 $(PROJNAME_KEYWORD) from
$(call GetPropValue, $(PROJNAME_KEYWORD))
那么在这种情况下,该怎么写呢?
总结
既然要获取记录在C头文件中的宏定义数据,最自然的应用工具就是C预处理器。那么完全跳过 user-defined 函数并使用
怎么样?
PROJNAME = $(shell echo PROJNAME | cat version.h - | cpp -P | tr -d '"')
说明
您已经在使用 GNU 版本的 make
,尤其是其 $(shell)
功能。 $(shell)
执行 shell 命令并计算命令标准输出的内容。在这种情况下,执行的命令决定了version.h
中定义的预处理器宏的定义
将 version.h
的内容与包含裸宏名称的行连接起来,并且
将结果通过管道输送到预处理器中。预处理器的 -P
选项会抑制额外输出的生成,例如 line-number 指标。
宏定义包含的引号不是您要分配给 make
变量的值的一部分,因此预处理器输出进一步通过管道传输到 tr
中以去除这些引号。
演示
给定这个完整的 makefile ...
PROJNAME = $(shell echo PROJNAME | cat version.h - | cpp -P | tr -d '"')
demo:
@echo '$(PROJNAME)'
... ,并且问题中出现的 version.h
文件位于同一目录中, 运行 make
或 make demo
产生此输出:
Uranium
我改天试了,
if (index(words[i], $$(1)) != 0) { \
$$(1)不正确,应替换为$(1),
if (index(words[i], $(1)) != 0) { \
但这会导致另一个问题,
当 makefile 在 运行,
之前进行静态检查时会发生很多错误
awk: line 1: syntax error at or near )
awk: line 1: syntax error at or near }
这意味着静态检查不知道它是 $(1),可能会替换为空,但我不确定,
要解决此问题,请在 $(1) 之前添加 "",
所以应该是这样的,
if (index(words[i], ""$(1)) != 0) { \
静态检查没问题,$(1)会被argv[1]正确替换
项目中有一个version.h文件,像这样:
#ifndef _VERSION_H_
#define _VERSION_H_
#define PROJNAME "Uranium"
#define VERSION "1.0.1"
#endif
而且我想在使用make编译项目时打印项目名称和版本。 所以我添加了以下 makefile:
PROJNAME_KEYWORD = "PROJNAME"
VERSION_KEYWORD = "VERSION"
define GetPropValue
$(shell \
awk '{ \
split($[=11=], words, " "); \
for (i in words) { \
if (index(words[i], $$(1)) != 0) { \
word = words[i + 1]; \
gsub("\"", "", word); \
print word; \
break; \
} \
} \
}' version.h \
)
endef
ifndef PROJNAME
PROJNAME = $(call GetPropValue, $(PROJNAME_KEYWORD))
endif
ifndef VERSION
VERSION = $(call GetPropValue, $(VERSION_KEYWORD))
endif
预计会有这个:
PROJNAME = Uranium
VERSION = 1.0.1
但实际上我得到了这个,
PROJNAME=_VERSION_H_ _VERSION_H_ PROJNAME VERSION
VERSION=_VERSION_H_ _VERSION_H_ PROJNAME VERSION
经过一些调试过程,我在
中找到了$$(1)if (index(words[i], $$(1)) != 0) {
行不正确, 当我用 "PROJNAME" 替换 $$(1) 时, 我可以得到正确的结果,
PROJNAME = Uranium
$$(1) 应该是参数,比如 $(PROJNAME_KEYWORD) from
$(call GetPropValue, $(PROJNAME_KEYWORD))
那么在这种情况下,该怎么写呢?
总结
既然要获取记录在C头文件中的宏定义数据,最自然的应用工具就是C预处理器。那么完全跳过 user-defined 函数并使用
怎么样?PROJNAME = $(shell echo PROJNAME | cat version.h - | cpp -P | tr -d '"')
说明
您已经在使用 GNU 版本的 make
,尤其是其 $(shell)
功能。 $(shell)
执行 shell 命令并计算命令标准输出的内容。在这种情况下,执行的命令决定了version.h
中定义的预处理器宏的定义
将
version.h
的内容与包含裸宏名称的行连接起来,并且将结果通过管道输送到预处理器中。预处理器的
-P
选项会抑制额外输出的生成,例如 line-number 指标。
宏定义包含的引号不是您要分配给 make
变量的值的一部分,因此预处理器输出进一步通过管道传输到 tr
中以去除这些引号。
演示
给定这个完整的 makefile ...
PROJNAME = $(shell echo PROJNAME | cat version.h - | cpp -P | tr -d '"')
demo:
@echo '$(PROJNAME)'
... ,并且问题中出现的 version.h
文件位于同一目录中, 运行 make
或 make demo
产生此输出:
Uranium
我改天试了,
if (index(words[i], $$(1)) != 0) { \
$$(1)不正确,应替换为$(1),
if (index(words[i], $(1)) != 0) { \
但这会导致另一个问题, 当 makefile 在 运行,
之前进行静态检查时会发生很多错误awk: line 1: syntax error at or near )
awk: line 1: syntax error at or near }
这意味着静态检查不知道它是 $(1),可能会替换为空,但我不确定, 要解决此问题,请在 $(1) 之前添加 "", 所以应该是这样的,
if (index(words[i], ""$(1)) != 0) { \
静态检查没问题,$(1)会被argv[1]正确替换