Parse runtime created file in makefile script - makefile

I am writing a makefile script which should be able to parse a file which is created by the same makefile. I am using following code to parse $(FileName) file. When I execute I see **cat: InputFile:No such file or directory**. This code works fine for already existed file, but not working if file is not exist before I run make. Could you please suggest how can I resolve this issue? Thanks in advance.
Snippet from the Makefile -
test_connection:
. . .
//Create file named $(Filename)
. . .
$(call generate_list,$(FileName))
define generate_list
$(eval FILE_DATA= $(shell cat $(DIR)/$1); \
$(foreach word, $(FILE_DATA), \
. . .
endef

Your problem is that you are crossing boundaries. make parsing and processing happens before any rule bodies are run. target rule bodies are only run after that. So you can't create a file in a target rule body and expect it to be available for usage during make context (without using an included makefile but we'll get to that in a minute).
The simplest solution to this problem is simply to move the parsing out of make entirely and just do it in a shell (or other) script. This obviously doesn't work if you need the contents for some make-level decisions/etc. though.
The other possible solution is to use an included makefile and take advantage of the fact that when make rebuilds an included makefile it will restart its processing from the beginning (which then makes the contents of that makefile available from the start). To do this you would:
add an include $(Filename) line in your makefile
create a $(Filename): target with a rule to build it
parse the file (when it exists) in the top-level of your makefile
do what you need with the parsed data (in some makefile variables I assume) in the test_connection rule

Related

Makefile rule only works if file exists before make is invoked

Consider the following (MCVE of a) Makefile:
my_target: prepare test.bin
prepare:
echo >test.dat
%.bin: %.dat
cp $? $#
If you run make in a clean directory, it fails:
echo >test.dat
make: *** No rule to make target 'test.bin', needed by 'my_target'. Stop.
Run it again and it succeeds:
echo >test.dat
cp test.dat test.bin
What seems to happen is that the rule to make *.bin from *.dat only recognises that it knows how to make test.bin if test.dat exists before anything is executed, even though according to the output it has already created test.dat before it tries to create test.bin.
This is inconvenient for me as I have to prepare a few files first (import them from a different, earlier part of the build).
Is there a solution? Perhaps some way to allow the rules to be (re)evaluated in the light of the files which are now present?
There are a number of issues with your makefile. However based on your comments I'm inclined to assume that the MCVE here is just a little too "M" and it's been reduced so much that it has a number of basic problems. So I won't discuss them, unless you want me to.
The issue here is that you're creating important files without indicating to make that that's what you're doing. Make keeps internally a cache of the contents of directories that it's worked with, for performance reasons, and that cache is only updated when make invokes a rule that it understands will modify it.
Here your target is prepare but the recipe actually creates a completely different file, test.dat. So, make doesn't modify its internal cache of the directory contents and when it checks the cache to see if the file test.dat exists, it doesn't.
You need to be sure that your makefile is written such that it doesn't trick make: if a recipe creates a file foo then the target name should be foo, not bar.
This happens for wildcard targets, like %.bin. They get evaluated at the first pass. You could add an explicit target of test.bin. Or, follow the advice of tkausl and have test.dat depend on prepare (a phony target). In this case, you don't need the double dependency anymore:
my_target: test.bin
you have to write
test.dat: prepare
or (when when you want to stay with wildcards)
%.dat: prepare
#:
Usually, you might want to create and use .stamp files instead of a prepare target.

Makefile pattern rules not working

I am learning makefiles, and can't just wrap my head around this problem i am having, and would like to understand how/why this fail.
I have half a dozen erlang files in a src directory. I want to compile these into a ebin directory, without having to define a rule for each and every one of them. According to the Gnu make documentation, pattern rules should be right up my alley.
However, with the following makefile, all I get from make is make: *** No targets. Stop. Why is that?
ebin/%.beam: src/%.erl
mkdir -p ebin
erlc -o ebin $<
Edit: Based on this answer, I now understand that i would have to explicitly declare the targets, for instance by using make ebin/cmplx.beam. However, i still do not understand how i should write my makefile to get my desired behaviour - since I have half a dozen targets (and in other projects even more), this seems like an unnecessary hassle. Is there not a way to define targets based on the source file names?
The target rule tells make that whenever it needs to produce a beam file in the ebin directory, and there exists a corresponding erl file in the src directory, it can use erlc.
However, this doesn't tell make that this is what it needs to do. You could explicitly tell make what it needs to do by giving it a target on the command line:
make ebin/foo.beam
If you don't give a target on the command line, make will pick the first non-pattern rule in the makefile as its target. However, your makefile doesn't have any non-pattern rules, so there is no target.
What you probably want is that for each existing erl file in src, make should consider the corresponding beam file in ebin to be a target. You can achieve that by calling wildcard and patsubst:
erl_files=$(wildcard src/*.erl)
beam_files=$(patsubst src/%.erl,ebin/%.beam,$(erl_files))
ebin/%.beam: src/%.erl
mkdir -p ebin
erlc -o ebin $<
all: $(beam_files)
(The indented lines need to be actual physical tabs, not spaces.)
That way, running make will rebuild all beam files that are out of date. all gets chosen as the default target, and it in turn depends on all beam existing or potential, each of which in turn depends on the corresponding erl file.
This trick is described in the GNU make manual.

what is the meaning for . (dot) before the target in makefile

In a make file i found the code snip like below. Is there any difference between create_file and run_debug ? i mean the use of . (dot) before create_file introduce any functionality like PHONY?
all:debug run_debug
setup: .create_file
.create_file:
cd /home/user1
touch file.txt
run_debug:
#echo Building debug
cd /home/user1/debug
As far as I know it has only one purpose (and in this makefile that purpose is obviated by the makefile construction).
From How make Processes a Makefile:
By default, make starts with the first target (not targets whose names start with ‘.’). This is called the default goal.
So a leading . means that make will not consider that target as a valid default goal.
But, as written, the all target is the first target in this makefile so that will be the default goal so the leading dot here doesn't actually do anything.
That said all three of the setup, run_debug and .create_file targets should be marked as .PHONY and may have much better ways of being written/etc.
In addition to the default goal use, I also found it convenient that targets beginning with a . are not displayed in auto-completion, i.e. typing make + Tab
So I prefix targets that are not meant for the end user with a .

Test if files in another directory exist in makefile

How would one test for the existence of files with a certain extension (.cpp in this case) in a directory at a specified location which is several directories down from the location of the makefile? I would like to print(echo) a message out if they are found
Your question is ambiguous. You mean, inside a make recipe you want to perform this test? If so then just write the appropriate shell scripting to check for the existence of said files.
If you mean outside of any recipe, in the makefile itself, if you're using GNU make you can use the $(wildcard ...) function:
ifneq (,$(wildcard some/sub/directory/*.cpp))
$(info found some cpp files!)
endif

Importing a generated makefile

I have a Makefile that imports another Makefile that is generated by a target in the containing one. Something like the following:
more_makefile:
touch $#
include more_makefile
This process works fine, but you get a warning No such file or directory every time you hit the include line when more_makefile doesn't exist, which can confuse newcomers. Is there a way to mask this warning?
Add a hyphen:
-include more_makefile

Resources