makefile如何将自定义变量写入yaml文件以支持vagrantfile fetch参数

How does the makefile write user-defined variables to the yaml file to support vagrantfile fetch parameters

我有一个项目是用makefile来控制vagrant的,我想把vagrant的参数放到makefile里面,比如cpu, memory, ip, [=15] =]、forwarded_port 等。我找到了一个 way,vagrantfile 读取 yaml 文件来参数化 vagrantfile。因此 makefile 需要一个 target 来读取所有用户选项变量并将它们作为 key-value 对写入 config.yaml。

样本如下

# === BEGIN USER OPTIONS ===
BOX_OS ?= fedora
# Box setup
#BOX_IMAGE
# Disk setup
DISK_COUNT ?= 1
DISK_SIZE_GB ?= 25
# VM Resources
MASTER_CPUS ?= 2
MASTER_MEMORY_SIZE_GB ?= 2
NODE_CPUS ?= 2
NODE_MEMORY_SIZE_GB ?= 2

NODE_COUNT ?= 2
# Network
MASTER_IP ?= 192.168.26.10
NODE_IP_NW ?= 192.168.26.
POD_NW_CIDR ?= 10.244.0.0/16

...
...
# === END USER OPTIONS ===

echo 命令确实实现了它

# Makefile
envInit:
    @echo "POD_NW_CIDR : \"$(POD_NW_CIDR)\"" > ${FILECWD}/configs.yaml

但是 too many variables 可能太复杂了。

有没有办法批量读取变量及其值并将它们写入 yml 文件

如果你们能告诉我如何实现批量读取变量及其值并将它们写入 yml 文件,我将不胜感激。

将所有用户选项(连同默认值)定义为一个列表,以便它们是可迭代的:

# list of user options with default values
userOptions = \
  BOX_OS=2 \
  DISK_COUNT=1 \
  MASTER_IP=192.168.26.10

# replace each default value with the env value, if any
userOptionValues = $(foreach i, $(userOptions), \
  $(word 1, $(subst =, ,$i))=$(or \
      $($(word 1, $(subst =, ,$i))), $($(word 1, $(subst =, ,$i))), $(word 2, $(subst =, ,$i))))

# write the yaml file
envInit:
# empty the file
    @printf "" > configs.yaml
# write a line for each option
    @for i in $(userOptionValues); do \
        printf "%s : %s\n" "$$(printf $$i | cut -d= -f1)" "$$(printf $$i | cut -d= -f2)" >> configs.yaml; \
    done

@flyx 谢谢你的回答,你的代码确实很好用。不过我好像找到了更多的convenient way,我也修改了一部分

printvars:
    @echo$(foreach V,$(sort $(.VARIABLES)), \
        $(if $(filter-out environment% default automatic,$(origin $V)),$(info $V: $($V))))

但离实现目标还有差距

# the Makefile test file
FILECWD = $(shell pwd)

# === BEGIN USER OPTIONS ===
CLOUD_IP ?= 192.168.79.222
CLOUD_NAME ?= cloud
CLOUD_CPU ?= 6
CLOUD_MEMORY ?= 8


# === END USER OPTIONS ===

printvars:  
    @echo$(foreach V,$(sort $(.VARIABLES)), \
        $(if $(filter-out environment% default automatic,$(origin $V)),$(info $V: $($V))))

make printvars 的输出包含许多其他变量

$ make printvars 
.DEFAULT_GOAL: printvars
CLOUD_IP: 192.168.79.222
CLOUD_MEMORY: 8
CLOUD_NAME: cloud
CURDIR: /testmakecreateyml0930
FILECWD: /testmakecreateyml0930
GNUMAKEFLAGS: 
MAKEFILE_LIST:  Makefile
MAKEFLAGS: 
SHELL: /bin/sh

而且只能打印不能导出到yamlfile.This离成功只差一步

如果你能帮我修改它以实现我的目标,我将不胜感激

您可以使用 GNUmakes $(file) 函数直接写入文件:

define newline :=
$(strip)
$(strip)
endef
space := $(strip) $(strip)#
-never-matching := ¥# character 165, this is used as a list element that should never appear as a real element

option-names = $(subst $(-never-matching),,$(filter $(-never-matching)%,$(subst $(-never-matching)$(space),$(-never-matching),$(-never-matching)$(strip $(subst $(newline), $(-never-matching),)))))


# define your user options in as many separate parts as you like, spaces and empty lines included:
define USER_OPTIONS +=
a = spaces are no problem

b = "neither nearly all 'other' characters: 8&)("
endef

define USER_OPTIONS +=

c = baz baf
d = foobar
endef

# make all definition make variables verbatim 
$(eval $(USER_OPTIONS))

YAML_FORMAT := $(foreach name,$(call option-names,$(USER_OPTIONS)),$(newline)$(name) : $($(name)))

# write the file. Warning: this happens before any rule is run!
$(file >test.yaml,$(YAML_FORMAT))

$(info $(foreach name,$(call option-names,$(USER_OPTIONS)),<$(name) : $($(name))> ))

诀窍在于将所有相关的用户选项变量聚集在一个多行 make 变量中。函数 option-names 将该变量中的所有标识符提取到一个单独的列表中。

我从 the GNUmake table toolkit 中获取了 newline 等字符定义,它对 "programmatic" make 有很多功能。