How can I create a variable on-the-fly from makefile, the value of which would be the entire contents of another data file.
8 Answers
Assuming GNU make:
file := whatever.txt
variable := $(shell cat ${file})

- 131,725
- 17
- 180
- 271
-
4@ceving Use the standard GNU make. Solaris make is a non-portable application. – Maxim Egorushkin Nov 12 '15 at 13:12
-
11Gnu make is neither standard nor more portable than solaris make. "Popular" is your word. If we seriously consider portability and standard conformation, stick with posix. – 把友情留在无盐 Dec 16 '17 at 01:27
-
4I'd go with "Popular" in this case - non-GNU Make is just too primitive. If you're aiming to continue supporting 1990s operating systems, then @bb-generation's answer is probably what you need (though it will get you in trouble in many cases). In all other cases, GNU Make is either easily available or - more likely - the default, so please make use of it. – Guss Jul 02 '19 at 07:06
-
3GNU make runs anywhere so yes it's much more portable than any other make. "standard" can be subjective, granted. – MarcH Jul 06 '20 at 19:42
I'm guessing that you like to set a variable in your Makefile to the contents of another file:
FILE=test.txt
VARIABLE=`cat $(FILE)`
target:
echo $(VARIABLE)

- 1,487
- 12
- 9
-
1That's what I have been trying but I get the error: "'VARIABLE' is not recognized as an internal or external command, operable program or batch file." Please keep in mind that I am using GNU make Windows and I am trying to do this from one of my Targets: all: VARIABLE=`cat $(PATH_TO_MY_DATA_FILE)` – Srinath Jul 20 '11 at 20:04
-
1You have put the variable definition above the `all:`, right? [edit] Just edited the answer to my local test-Makefile which works using GNU Make Windows 3.81 – bb-generation Jul 20 '11 at 20:29
-
3Actually, I cannot put the VARIABLE definition above all: because PATH_TO_MY_DATA_FILE does not exist until some commands have been run in the all: target. As an alternative, what I have done is that I have split things up into two makefiles (created a sub-make) and declared the VARIABLE at the top of the sub-make and it now works like a charm. – Srinath Jul 21 '11 at 18:31
-
30This is a wrong answer. The value of `VARIABLE` is a string ``cat $(FILE)`` (in quotes) which only gets expanded in a recipe by the shell. Try printing the value of it like `$(info ${VARIABLE})`. – Maxim Egorushkin Aug 20 '13 at 12:21
-
4@MaximEgorushkin It is not wrong. You just have to consider `VARIABLE` as a promise. This is the only version which works with older versions of `make`. Both `:=` and `$(shell ...)` are GNU extensions. – ceving Nov 12 '15 at 13:06
-
@ceving Original question is _variable ... the value of which would be the entire contents of another data file_. In other words, the value is the contents, not the command to read the contents. – Maxim Egorushkin Nov 12 '15 at 13:11
-
7Downvoted. This will execute `cat` every time the rule is executed. This is usually not be intended and should be warned against, because it's slow. Besides, if the file is a pipe, it has unintended side-effects. The assignment should be with `:=` so that the rule would not get evaluated when the variable is replaced but when the variable is defined. The replacement value should be `$(shell cat $(FILE))` so that the `cat` command is executed in-place by make, not later by the recipe rules. – Christian Hujer Feb 22 '17 at 13:34
-
Why do people on here always assume that everyone in the world runs a UNIX / Linux-based system that has stuff like cat?? – antred Nov 08 '18 at 11:02
-
as @MaximEgorushkin says, this _is_ the wrong answer. Although this _will_ work in shell sections of a makefile, if you use the value elsewhere, for example in filename, or if you use it within single quotes in the shell then the value you will get is exactly `cat $(FILE)` which is horribly wrong. – Michael Jan 26 '19 at 11:54
-
2@antred , make is part of the standard UNIX/POSIX toolset which also includes cat. If you install make it's normal to install all the other basic tools and there are very rare circumstances where that will cause any difficulties. Relying on `cat` rather than complex alternate rules will make your makefiles much simpler to understand and almost as portable or sometimes more portable. – Michael Jan 26 '19 at 11:56
GNU make version 4.2 supports file reading operation, so with respect to Maxim Egorushkin's great answer there is an optional way to solve this problem now:
FILE := test.txt
variable :=$(file < $(FILE))

- 1,695
- 2
- 23
- 31

- 511
- 4
- 2
-
Fixed an error. Variable names are case-sensitive. The names ‘foo’, ‘FOO’, and ‘Foo’ all refer to different variables. (https://www.gnu.org/software/make/manual/html_node/Using-Variables.html) – Yaroslav Nikitenko Oct 12 '18 at 10:07
-
quotes are also not needed, $(file < "$(FILE)") tries to open "test.txt". – cagney Sep 27 '19 at 18:04
-
1This is superior to the "shell cat" answers in the case where the file contains newlines and you want them to be preserved – telent Nov 01 '21 at 14:55
-
cat
doesn't exist on Windows. Solution that works for Linux and Windows:
cat := $(if $(filter $(OS),Windows_NT),type,cat)
variable := $(shell $(cat) filename)
Explanation:
Seems like On Windows there is always OS
environment variable defined to be equal to 'Windows_NT'. This way, for Windows type
command is used, for non-Windows cat
is used.

- 15,789
- 11
- 79
- 128
Much simpler since $(file op filename)
was added:
VARIABLE = $(file < my_file.txt)
Manual page here: https://www.gnu.org/software/make/manual/html_node/File-Function.html#index-file_002c-reading-from

- 3,287
- 31
- 26
-
1This worked for me under GNU Make 4.2.1, unlike the other suggested solutions :) – TabeaKischka Sep 19 '18 at 14:03
-
5This was introduced in GNU Make 4, and macOS still ships with 3.81 in 2019 :-( – MichielB Jul 09 '19 at 09:56
-
1
-
If you are using GNU make, another way to get this effect is to use a make "include" of another makefile:
From Makefile:
include "./MyFile.mak"
Create a file "MyFile.mak" with content:
FILE := "my file content"
FILE += "more content 1"
FILE += "more content 2"

- 5,987
- 2
- 39
- 61
-
this doesn't seem to work, I get `Makefile:1: "./MyFile.mak": No such file or directory` – knocte Jun 06 '19 at 13:06
-
that probably means you are using a none GNU version of make.... or a really old version of GNU make... try: "make -v" – Bimo Jun 06 '19 at 14:55
-
using make in mac, not sure if bundled or installed by homebrew, `make -v` gives `GNU Make 3.81` – knocte Jun 06 '19 at 15:04
-
do you make sure you have not accidently converted TAB characters into SPACE characters in the Makefile? Make is almost annoying as python in this regards. – Bimo Jun 12 '19 at 16:58
-
3I got this to work by on my Mac by removing the quotes, e.g.: `include ./MyFile` – Charlie Tran Jul 15 '19 at 04:15
As the platform has not been specified, this is the way how it works on Solaris:
VERSION:sh = cat VERSION
all:
echo $(VERSION)

- 21,900
- 13
- 104
- 178
Here's a more portable solution, which works with MAKE
version 3, where file
directive isn't available. The downside is that it requires creating a temporary file in the process.
$(shell echo define my_variable > file.tmp)
$(shell cat my_file.txt >> file.tmp)
$(shell echo endef >> file.tmp)
include file.tmp
The main idea is to use define
directive, which is specifically designed to declare multiline variables. Of course, you can avoid using shell
and a temporary file if you can explicitly write file contents for Makefile usage.
Keep in mind that, if your file contains $
signs, MAKE
will try to expand them as variables/directives when my_variable
is expanded (or when assigned, of you define it with :=
). If you want to avoid it, you need to escape them before including file contents. For example, instead of cat
you can do this:
$(shell sed 's/\$$/$$$$/g' my_file.txt >> file.tmp)

- 1,471
- 1
- 13
- 17