Writing out dependencies into a file using Make - makefile

I'm writing a Makefile for Verilog compilation (isn't important if you aren't familiar with it). The compiler command can either take compile units or a flat file that has the compile units 'in order'. For the latter case, I'd like to write a rule that will spit out a file that has the dependencies in the right order.
Let's assume a simple makefile below:
a.output:
<a.files>
b.output: a.output
<b.files>
c.output: d.output
<c.files>
d.output: d.input
<d.files>
What I'd like is a file that contains:
a.files
b.files
d.files
c.files
An idea I had was to have a variable in the recipe that can be appended to, like
a.output:
MY_FILES += <a.files>
but I don't think that will work in a recipe context. Does anyone have a decent solution to this problem?
Also, I'd like the Makefile to be parallel but obviously it won't work for this target. How can I specify disabling parallel execution for this specific target or set of targets?
EDIT Oct 8 2019
To make it simpler for a person not familiar with Make syntax to write dependencies, I've basically let them write out their intent using variables:
MODULES += module_a
module_a.prerequisites = module_b module c
module_a.other_var = some_string_a
MODULES += module_b
module_b.prerequisites =
module_b.other_var = some_string_b
I then use a define directive to generate the rules necessary for compilation (I was inspired by this example). This means I do have flexibility on what I can create. So, in the previous example, <a.output> is actually the target for module_a. This can be a PHONY target. <a.files> actually represents the variables (prerequisites and other_var in the example).
I'm sorry for the miscommunication but what I'm trying to do is write out all the target and dependent module_x.other_var in the right order for a given module. I hope that makes it clear.
I'm currently concatenating a file in the right order which is one of the solutions mentioned below. I was wondering if there's some other Make magic that I could apply.

In its simplest form, you can just echo the names to the file
OUTPUT_FILE = output.file
a.output:
echo "<a.files>" > $(OUTPUT_FILE)
b.output: a.output
echo "<b.files>" >> $(OUTPUT_FILE)
c.output: d.output
echo "<c.files>" >> $(OUTPUT_FILE)
d.output: d.input
echo "<d.files>" >> $(OUTPUT_FILE)
If these files are prerequisites then you can print each dep or target using the auto vars:
Print the target/goal
d.output: d.input
echo "$#" >> $(OUTPUT_FILE)
print the first prerequisite
d.output: d.input
echo "$<" >> $(OUTPUT_FILE)
print all prerequisites
d.output: d.input
echo "$^" >> $(OUTPUT_FILE)
update for parallel build
Not pretty, can certainly improve this, but this will be safe for parallel builds. However as I say I think the echo method alone seems to work ok.
Also note this is not tested, so treat as pseudo code
OUTPUT_FILE = output.file
OUTPUT_FILE_A = output.file.a
OUTPUT_FILE_B = output.file.b
OUTPUT_FILE_C = output.file.c
OUTPUT_FILE_D = output.file.d
OUTPUT_FILES = $(OUTPUT_FILE_A)
OUTPUT_FILES += $(OUTPUT_FILE_B)
OUTPUT_FILES += $(OUTPUT_FILE_C)
OUTPUT_FILES += $(OUTPUT_FILE_D)
final: a.output b.output c.output d.output
echo "" > $(OUTPUT_FILE)
for file in "$(OUTPUT_FILES)" ; do \
cat $$file >> $(OUTPUT_FILE) ; \
done
a.output:
echo "<a.files>" > $(OUTPUT_FILE_A)
b.output: a.output
echo "<b.files>" > $(OUTPUT_FILE_B)
c.output: d.output
echo "<c.files>" > $(OUTPUT_FILE_C)
d.output: d.input
echo "<d.files>" > $(OUTPUT_FILE_D)

Related

Doxygen print bash file contents

I have a project with bash, python, and C files where I would like to simply print the contents of the bash file in the doxygen documentation.
I am using Doxygen 1.9.4 and my Doxyfile has the following modified settings:
JAVADOC_AUTOBRIEF = YES
PYTHON_DOCSTRING = NO
OPTIMIZE_OUTPUT_JAVA = YES
EXTENSION_MAPPING = sh=C
EXTRACT_ALL = YES
SORT_BRIEF_DOCS = YES
INPUT = .
FILTER_PATTERNS = *.sh="sh_filter"
FILE_PATTERNS += *.sh
The sh_filter file has the following contents
#!/bin/bash
echo "\verbatim"
echo "$(cat $1)"
echo "\endverbatim"
After running doxygen, there is nothing that appears in the file reference for the bash file that is within the working directory.
How can I get the file contents to be printed verbatim?
A bit long for a comment. The construction as requested is quite unusual as normally the purpose is to document routines / variables / classes / namespaces etc and support this with code. In this case the requirement is to just show the contents of the file.
The bests solution I found is to create the filter like:
#!/bin/bash
echo "/** \file"
echo "\details \verbinclude $1 */"
echo "$(cat $1)"
and have the following added to the doxygen settings file:
EXTENSION_MAPPING = sh=C
INPUT = .
FILTER_PATTERNS = *.sh="./sh_filter"
FILE_PATTERNS += *.sh
EXAMPLE_PATH = .
(where the different paths are depending on the local situation)

Makefile ifeq always true

I have the following Makefile target:
target1:
$(eval count_abc := $(shell grep -c "ABC" myFileA))
$(eval count_def := $(shell grep -c "DEF" myFileB))
echo $(count_abc)
echo $(count_def)
ifeq ($(count_abc),$(count_def))
echo "TRUE"
else
echo "FALSE"
endif
But the output is always TRUE, e.g.:
echo 22
22
echo 21
21
echo TRUE
TRUE
What am I doing wrong here? What I want is INSIDE the target do 2 greps and compare their outputs and do something or something else based on the result. Please note that the greps must be done within the target since myFileA and myFileB get created on the target before and don't exist at the beginning when running make.
Thanks,
Amir
The rule file for "make" is declarative in nature - the makefile defines rules and targets, and then the make program evaluate the rules, and decide which action to take based on the target. As a result, execution is not always in the order the lines are entered into the file.
More specifically, the "ifeq" is evaluated at the rule definition stage, but the actions for building the target (eval count_abc ...) are executed when the target is built. As a result, when the ifeq is processed, both count_abc and count_def are still uninitialized, expanded to empty strings.
For the specific case you described - building a target that will compare the grep -c output from the two files, you can try something like below, effectively using shell variables (evaluated when target is evaluated), and not make variables (which are mostly declarative, evaluated when makefile is read)
target1:
count_abc=$(grep -c "ABC" myFileA) ; \
count_def=$(grep -c "DEF" myFileB) ; \
echo $(count_abc) ; \
echo $(count_def) ; \
if [ "$count_abc" -eq "$count_def" ] ; then echo TRUE ; else echo FALSE ; fi
Disclaimer: I did not run the revised makefile, not having access to desktop at this time.

Makefile does not find target

I have the following Makefile, but it does not work. When I call
make html
I get a
make: *** No rule to make target `docs/index.html', needed by `html'. Stop.
error, even though I think I have defined it.
SRCDIR = source
OUTDIR = docs
RMD = $(wildcard $(SRCDIR)/*.Rmd)
TMP = $(RMD:.Rmd=.html)
HTML = ${subst $(SRCDIR),$(OUTDIR),$(TMP)}
test:
echo $(RMD)
echo $(TMP)
echo $(HTML)
all: clean update html
html: $(HTML)
%.html: %.Rmd
echo $(HTML)
#Rscript -e "rmarkdown::render('$<', output_format = 'prettydoc::html_pretty', output_dir = './$(OUTDIR)/')"
update:
#Rscript -e "devtools::load_all(here::here()); microcosmScheme:::updateFromGoogleSheet(token = './source/googlesheets_token.rds')"
## from https://stackoverflow.com/a/26339924/632423
list:
#$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$#$$' | xargs
.PHONY: update clean cleanhtml all list
The variables seem to be correct:
15:21 $ make test
echo source/index.Rmd
source/index.Rmd
echo source/index.html
source/index.html
echo docs/index.html
docs/index.html
If I change it as follow it works, but the target points to the SRCDIR, but I want it to point to the OUTDIR:
RMD = $(wildcard $(SRCDIR)/*.Rmd)
HTML = $(RMD:.Rmd=.html)
# HTML = ${subst $(SRCDIR),$(OUTDIR),$(TMP)}
I am sure it is one small thing...
This rule:
%.html : %.Rmd
....
tells make how to build a file foo.html from a file foo.Rmd, or a file source/foo.html from a file source/foo.Rmd, or a file docs/foo.html from a file docs/foo.Rmd.
It doesn't tell make how to build a file docs/foo.html from a file source/foo.Rmd, because the stem that matches the pattern % is not the same.
If you want to write a pattern for docs/foo.html to be built from source/foo.Rmd, you have to write it like this:
$(OUTDIR)/%.html : $(SRCDIR)/%.Rmd
....
so that the part that matches the pattern % is identical.
ETA Some other notes: you should be using := with the wildcard function as it's much better performing. Also you shouldn't use subst here because it replaces all occurrences of the string which could break things if any of your .Rmd files contain the string source for example (e.g., source/my_source_file.Rmd. This is much better written with patsubst, as in:
RMD := $(wildcard $(SRCDIR)/*.Rmd)
HTML := $(patsubst $(SRCDIR)/%.Rmd,$(OBJDIR)/%.html,$(RMD))
Finally, you don't show what the clean target does but it's unusual to have the clean target depended on by all. Usually it's a separate target that is invoked only when you want it, like make clean.

Makefile: read input variable and set several variables

I have a makefile where I want to read file name from input and then make other names based on it`s name. I have tried the following code
mlext = .ml
testext = test.ml
nativeext = test.native
test:
#read -p "Enter file name: " file; \
echo $$file$(mlext); \
echo $$file$(testext); \
echo $$file$(nativeext)
for example:
If i type: foo
then I want to get foo.ml, footest.ml, footest.native
however, I can only get foo.ml. For the rest two i only get .ml and .native
How can i fix this?
First, let us see what is the exact recipe given to the shell by removing the # in your Makefile:
read -p "Enter file name: " file; \
echo $file.ml; \
echo $filetest.ml; \
echo $filetest.native;
The issue is thus that the content of $(testext) gets appended to $$file, creating the shell variable $filetest, which (very probably) does not exist, resulting in an empty string in the end. This does not occur with $(mlext), as the initial dot cannot be part of a variable name.
To overcome this, use $${file} instead of $$file in your Makefile rule.

GNU override target?

I'm wondering if it's possible to override a target in a makefile! The environment I'm working in does not allow me to do this due to auto generation! I was wondering if I coded the same rule above or below the static target would this achieve an override?
%_emul.flist: $(if ${GEN_FLIST},%_synth.flist,) ${rdlh_file_deps}
${QUIET}if test ${SYN_DEBUG} -eq 1 ; then set -xv ; fi; \
$(if ${TOOL_VERILOG},rm -f $#; touch $#,$(if ${TOOL_BBOX_LIBS},echo ${TOOL_BBOX_LIBS} > $#,rm -f $#; touch $#))
/bin/sed -e '/\/libs\//d' -e '/\/place\//d' $(foreach mod,$(filter %.vhd,$^),-e 's%^\(.*\/\)\{0,1\}$(basename $(notdir ${mod}))\.v$$%${mod}%') $*_synth.flist >> $#
Yes , i think that would work .... but you need to be a bit more careful in the way you code things. You don't want to override something that might be useful!
GNU make would take the most recent of the target it encounters. So, the following works (but not as i would have liked it to work :( )
Output: I think you are looking for something like this --
Kaizen ~/make_prac $ make -nf mk.name
mk.name:20: warning: overriding recipe for target `name'
mk.name:17: warning: ignoring old recipe for target `name'
arg1="Kaizen" ;
echo "hello "" ;" ;
hello ;
Code: Here the target "name" appears twice and is overridden.
Kaizen ~/make_prac $ cat mk.name
##
## make to accept name and display hello name
##
arg1="" ;
.PHONY : name \
hello
#.DEFAULT :
# hello
hello : name
+ echo "hello $(arg1)" ;
name :
echo "name given is : $(arg1)" ;
name :
arg1="Kaizen" ;
PS: Take note of the use of : -- if you use :: then both rules get executed.
Explanation for the arg1 .... not showing in the output: The variable arg1, even though it gets assigned in the first parsing, it gets ignored, since its assignment is target dependent. If you would have had a variable declaration elsewhere -- e.g. like arg1 is defined at the start -- there would not be any dereferencing issues.

Resources