59

How can I list the current value of all variables (also called macros) in a Makefile when running make?

E.g. if this is in the Makefile:

CUR-DIR := $(shell /bin/pwd)
LOG-DIR := $(CUR-DIR)/make-logs

Then I would like it to tell me:

CUR-DIR = /home/johv/src/test
LOG-DIR = /home/johv/src/test/make-logs
johv
  • 4,424
  • 3
  • 26
  • 42

8 Answers8

54

GNU make provides .VARIABLES which holds all global variables' names. However, this includes built-in variables(like MAKEFLAGS). If you have to exclude built-in variables, some filtering like the following might be needed. The following makefile prints user-defined variables(CUR-DIR, LOG-DIR) using info:

# Place this line at the top of your Makefile
VARS_OLD := $(.VARIABLES)

# Define your variables
CUR-DIR := $(shell pwd)
LOG-DIR := $(CUR-DIR)/make-logs

# Put this at the point where you want to see the variable values
$(foreach v,                                        \
      $(filter-out $(VARS_OLD) VARS_OLD,$(.VARIABLES)), \
      $(info $(v) = $($(v))))
Diomidis Spinellis
  • 18,734
  • 5
  • 61
  • 83
Ise Wisteria
  • 11,259
  • 2
  • 43
  • 26
  • How do I run it? Putting it in a `Makefile` and runnning "`make`" I just get "`make: *** No targets. Stop.`" – johv Aug 22 '11 at 08:02
  • 2
    Sorry, I forgot to mention, if your GNU make's version is 3.80 or lower, this answer doesn't work. – Ise Wisteria Aug 22 '11 at 09:10
  • Ah, yes I used 3.80. In 3.81 it worked. Also, I changed to CUR-DIR in the question. – johv Aug 22 '11 at 09:56
  • 1
    how do you write it to a file rather than just print it? – Jason S Oct 14 '15 at 17:43
  • 2
    @JasonS, have your shell handle it. `make > variables.txt` – JSBձոգչ Jan 02 '16 at 21:12
  • This is great, a target which displays this can look like `vars:; $(foreach v, $(filter-out $(VARS_OLD) VARS_OLD,$(.VARIABLES)), $(info $(v) = $($(v)))) @#noop to prevent make: Nothing to be done for 'vars'.` – bschlueter Aug 12 '17 at 23:34
  • Thank you for this little bit of code! I just wanted to let you know that I'm stealing this to use for debugging my own makefiles. Do you want this linked in the code or??? – Jordan Feb 19 '23 at 03:04
  • @Jordan: Sure, you are free to use the code without attribution. – Ise Wisteria Feb 20 '23 at 00:50
  • how do you assign the output of this to a variable? – red888 May 09 '23 at 19:27
39

Thanks to @Ise Wisteria, condensed down, this shows all variables, useful for large projects with multiple makefiles (Buildroot).

$(foreach v, $(.VARIABLES), $(info $(v) = $($(v))))

output: BR2_GCC_TARGET_TUNE = "cortex-a8" ...

If you get an error like: insufficient number of arguments (1) to function 'addprefix' this project had some broken variables... I trimmed the list of variables to show, only with a prefix BR2_

$(foreach v, $(filter BR2_%,$(.VARIABLES)), $(info $(v) = $($(v))))
Kevin
  • 2,761
  • 1
  • 27
  • 31
37

I ended up doing it like this:

gmake -pn | grep -A1 "^# makefile"| grep -v "^#\|^--" | sort | uniq > makevars.txt

which gives:

CUR-DIR := /home/johv/src/test
LOG-DIR := /home/johv/src/test/make-logs
MAKEFILE_LIST :=  Makefile
MAKEFLAGS = pn
SHELL = /bin/sh
VARS_OLD := [...]

gmake -pn is really verbose and looks kinda like this:

# environment
GNOME2_PATH = /usr/local:/opt/gnome:/usr:/usr/local:/opt/gnome:/usr
# automatic
@F = $(notdir $@)
# makefile
SHELL = /bin/sh
# default
RM = rm -f
johv
  • 4,424
  • 3
  • 26
  • 42
13

It's also doable without saving all the .VARIABLES and filtering them out.

Moreover, if one of the original .VARIABLES was modified in your makefile, the two most voted answers won't catch it.

Check out $(origin) function. This target filters out and prints all the variables that were defined in a makefile:

print_file_vars:
    $(foreach v, $(.VARIABLES), $(if $(filter file,$(origin $(v))), $(info $(v)=$($(v)))))

I get only a few excess variables this way: CURDIR SHELL MAKEFILE_LIST .DEFAULT_GOAL MAKEFLAGS.

One can replace file with environment or command line to print the respective kinds of variables.

Victor Sergienko
  • 13,115
  • 3
  • 57
  • 91
4

There are a lot of good answers here, but you're going to have problems using $($(v)) if some of your variables are of the recursive flavor. This is why you should use $(value $(v)).

This variation cleans this up a little bit, sorts variables by name and makes the output a bit more readable.

dump:
    $(foreach v, \
        $(shell echo "$(filter-out .VARIABLES,$(.VARIABLES))" | tr ' ' '\n' | sort), \
        $(info $(shell printf "%-20s" "$(v)")= $(value $(v))) \
    )
Daniel Santos
  • 3,098
  • 26
  • 25
1

Thanks to @kevinf for the great idea. I would suggest a minor change to prevent .VARIABLE itself from printing out in the variable list:

$(foreach v, $(filter-out .VARIABLES,$(.VARIABLES)), $(info $(v) = $($(v))))

WiiBopp
  • 2,750
  • 1
  • 14
  • 9
1

Thanks to @kevinf for the foreach solution -- if one wants to export this list as a somewhat machine-readable file, one will have a hard time with uneven quotes or newlines when using echo or printf, since Make isn't able to quote the data correctly -- one needs to use the $(file ...) function to write the data to avoid sh/bash complaining about invalid syntax. For example, use this in your rule -- it prints variable name, definition and expanded value:

$(file > $(MAKEFILE_ENV_FILE),)
$(foreach v, $(.VARIABLES), \
    $(file >> $(MAKEFILE_ENV_FILE),$(v)) \
    $(file >> $(MAKEFILE_ENV_FILE),    := $(value $(v))) \
    $(file >> $(MAKEFILE_ENV_FILE),    == $($(v))) \
    $(file >> $(MAKEFILE_ENV_FILE),) \
)

(This will still not allow to always distinguish malicious variables with double newlines from two variables, for this one now add a sufficiently unique separator infront of each Makefile-generated newline just after each comma inside $(file >> NAME,TEXT))

Set MAKEFILE_ENV_FILE to some filename, e.g.:

MAKEFILE_ENV_FILE := $(abspath $(lastword $(MAKEFILE_LIST))).env
phi1010
  • 678
  • 6
  • 13
1

This solution is an improvement of Ise Wisterias Solution:

./Makefile:

ARG_VARS_0 := $(.VARIABLES)
#############################
# Documented Arguments START
#############################

EXAMPLE_ARG_0 :=
EXAMPLE_ARG_1 := ./some/path

#############################
# Documented Arguments END
#############################
ARG_VARS_1 := $(.VARIABLES)
# filter out any words starting with '%':
ARG_VARS_0_FIXED := $(filter-out \%%,$(ARG_VARS_0))
ARG_VARS_1_FIXED := $(filter-out \%%,$(ARG_VARS_1))
ARG_VARS := $(filter-out $(ARG_VARS_0_FIXED) ARG_VARS_0,$(ARG_VARS_1_FIXED))

.PHONY: list_vars print_vars # ...

list_vars:
    $(foreach v,$(ARG_VARS),$(info $(v)))

print_vars:
    $(foreach v,$(ARG_VARS),$(info $(v) = $($(v))))

List makefile arguments on the terminal:

$ make list_vars
> EXAMPLE_ARG_0
> EXAMPLE_ARG_1

print makefile arguments default values on the terminal:

$ make print_vars
> EXAMPLE_ARG_0 =
> EXAMPLE_ARG_1 = ./some/path

The funny part with the '%' is necessary since .VARIABLES sometimes contain odd content, such as %D %F *D *F +D +F .... The words starting with % can cause problems otherwise (e.g. some variables just not being printed).

EsGeh
  • 11
  • 3