grep and sed in a Fortran Makefile - bash

I have a Fortran code that can be compiled by the following Makefile:
FC = mpif90
FFLAGS := ...
TARGET = run1
SRC = main.f90 param.f90 ...
OBJ = $(SRC:.f90=.o)
all: $(TARGET)
$(TARGET): $(OBJ) $(FC) $(FFLAGS)
...
In the above, the TARGET can be run1 or run2 or run3, depending on the value of a variable in my script. For example, if I have the following in param.f90:
character(len=1), parameter :: case_num = "1"
Then, I want the TARGET variable to be set as run1. Now, the question is how to do that automatically without manually changing the Makefile every time?
I have tried something like
num = $(grep 'case_num = "' param.f90 | sed -n -e 's/^.*case_num = "//p' | cut -c1-1)
TARGET = run$num
in the Makefile, which doesn't work. I have checked that the grep and sed sentence is correct in a regular bash script. How to do this in a Fortran Makefile? Any help is appreciated.

Your makefile appears to a GNU Make makefile. To assign the output of a
shell command to a make variable, you need to use the $(shell ...) function,
like:
num := $(shell grep 'case_num = "' param.f90 | sed -n -e 's/^.*case_num = "//p' | cut -c1-1)
TARGET := run$(num)

Related

GNU Makefile uses the same source file for all object files

File structure:
cpp
| Makefile
|
| obj
|___include
| | a.cuh
| | b.cuh
| | c.cuh
|
|___src
| | a.cu
| | b.cu
| | c.cu
I don't have much experience with GNU make. The following was written based on different search results on Stackoverflow. The $# variable correctly gets the name of each object file from the list, however $< variable only gets the first item in the list of source file names (as per the manual, but that is what all the stack overflow answers I found are using 1, 2, 3).
NVCC=nvcc
LIB = lib.dll
SRC_DIR = src
INC_DIR = include
OBJ_DIR = obj
CU_FILES = $(wildcard $(SRC_DIR)/*.cu)
CUH_FILES = $(wildcard $(INC_DIR)/*.cuh)
CUO_FILES = $(addprefix $(OBJ_DIR)/,$(notdir $(CU_FILES:.cu=.obj)))
$(LIB): $(CUO_FILES)
$(NVCC) --shared $^ -o $#
$(CUO_FILES): $(CU_FILES) $(CUH_FILES)
$(NVCC) -dc $< -o $#
What you wrote is probably not what you want. Your rule:
$(CUO_FILES): $(CU_FILES) $(CUH_FILES)
$(NVCC) -dc $< -o $#
means that each object file depends on all source files ad all header files.
What you need here is a pattern rule saying that obj/foo.obj depends on src/foo.cu and include/foo.cuh:
obj/%.obj: src/%.cu include/%.cuh
$(NVCC) -dc $< -o $#
Note that you can simplify a bit the CUO_FILES assignment:
CUO_FILES = $(patsubst $(SRC_DIR)/%.cu,$(OBJ_DIR)/%.obj,$(CU_FILES))

Variable substitution in Makefile target dependency

I have a Makefile with targets that have associated dependencies. So I use lookup table like:
APPS = a b c
dependency.lookup.a := x
dependency.lookup.b := y
dependency.lookup.c := z
$(APPS): %: path/$(dependency.lookup.%).datafile
do something with $(dependency.lookup.$#)
This makefile gives me error.
*** No rule to make target 'path/.datafile'
Constraints: Only MinGW. can't use shell/MSYS. Also support FreeBSD.
This requires using Secondary Expansion feature:
.SECONDEXPANSION:
$(APPS): %: path/$$(dependency.loopup.$$*).datafile
#echo "$# depends on $^"
%.datafile : # Create one on demand for testing.
mkdir -p ${#D}
touch $#
Outputs:
mkdir -p path/
touch path/x.datafile
a depends on path/x.datafile
Alternatively, use regular dependencies:
a : path/x.datafile
b : path/y.datafile
c : path/z.datafile
$(APPS): % :
#echo "$# depends on $^"
The top 3 lines only add dependencies, the rule is specified separately. The output is the same.
I had the same problem but with rather long names. I didn't want to repeat them (in APPS = ...), so I used a generated auxiliary makefile.
Makefile:
all: build
include deps.mk
deps.mk: deps.txt deps.sh
./deps.sh <$< >$#
build: $(DEPS)
echo "DEPS are up-to-date." # or whatever
deps.sh:
#!/bin/bash
echo "# This file is generated by $0"
echo "DEPS ="
while read -r dst src; do
echo
echo "DEPS += $dst"
echo "$dst: $src"
echo -e '\t''cp $< $#' # or whatever
done
deps.txt (now only this file needs to be updated for new dependencies):
a x
b y
c z

latex makefile not finding png: make: *** No rule to make target `pngfigure.pdf', needed by `main.pdf'. Stop

I'm having trouble getting one of my documents to compile. I've used this makefile before no problems. However, this time, It seems to have a problem recognising .png figures and tries to load them as .pdf.
main.tex
\documentclass[letterpaper, 10 pt, conference]{ieeeconf} % Comment this line out
% if you need a4paper
%\documentclass[a4paper, 10pt, conference]{ieeeconf} % Use this line for a4
% paper
\IEEEoverridecommandlockouts % This command is only
% needed if you want to
% use the \thanks command
\overrideIEEEmargins
% See the \addtolength command later in the file to balance the column lengths
% on the last page of the document
% The following packages can be found on http:\\www.ctan.org
\usepackage{graphics} % for pdf, bitmapped graphics files
\usepackage{epsfig} % for postscript graphics files
\usepackage{mathptmx} % assumes new font selection scheme installed
\usepackage{times} % assumes new font selection scheme installed
\usepackage{amsmath} % assumes amsmath package installed
\usepackage{amssymb} % assumes amsmath package installed
\usepackage{graphicx} % Include figures
\usepackage{float} % Include figures
\graphicspath{{./Figures/}} %Where the figures folder is located
\title{\LARGE \bf
.
.
.
\begin{document}
.
.
.
\begin{figure}[thpb]
\centering
\includegraphics[width=3in]{pngfigure}
\caption{pngfigure}
\label{fig:pngfigure}
\end{figure}
.
.
.
and my Makefile
# Makefile for LaTeX files
LATEX = pdflatex
BIBTEX = bibtex
MAKEINDEX = makeindex
OUTPUT_PDF_FILE_NAME = phd_conversion_report
RERUN = "(There were undefined references|Rerun to get (cross-references|the bars) right)"
RERUNBIB = "No file.*\.bbl|Citation.*undefined"
MAKEIDX = "^[^%]*\\makeindex"
MPRINT = "^[^%]*print"
USETHUMBS = "^[^%]*thumbpdf"
SRC := $(shell egrep -l '^[^%]*\\begin\{document\}' *.tex)
BIBFILE := $(shell perl -ne '($$_)=/^[^%]*\\bibliography\{(.*?)\}/;#_=split /,/;foreach $$b (#_) {print "$$b.bib "}' $(SRC))
PDFPICS := $(shell perl -ne '#foo=/^[^%]*\\(includegraphics)(\[.*?\])?\{(.*?)\}/g;if (defined($$foo[2])) { if ($$foo[2] =~ /.pdf$$/) { print "$$foo[2] "; } else { print "$$foo[2].pdf "; }}' *.tex)
DEP = *.tex
TRG = $(SRC:%.tex=%.pdf)
COPY = if test -r $(<:%.tex=%.toc); then cp $(<:%.tex=%.toc) $(<:%.tex=%.toc.bak); fi
RM = rm -f
OUTDATED = echo "EPS-file is out-of-date!" && false
all: $(TRG) copy clean
define run-latex
$(COPY);$(LATEX) $<
egrep -q $(MAKEIDX) $< && ($(MAKEINDEX) $(<:%.tex=%);$(COPY);$(LATEX) $<) ; true
egrep -c $(RERUNBIB) $(<:%.tex=%.log) && ($(BIBTEX) $(<:%.tex=%);$(COPY);$(LATEX) $<) ; true
egrep -q $(RERUN) $(<:%.tex=%.log) && ($(COPY);$(LATEX) $<) ; true
egrep -q $(RERUN) $(<:%.tex=%.log) && ($(COPY);$(LATEX) $<) ; true
if cmp -s $(<:%.tex=%.toc) $(<:%.tex=%.toc.bak); then true ;else $(LATEX) $< ; fi
$(RM) $(<:%.tex=%.toc.bak)
# Display relevant warnings
egrep -i "(Reference|Citation).*undefined" $(<:%.tex=%.log) ; true
endef
$(TRG): %.pdf: %.tex $(DEP) $(PDFPICS) $(BIBFILE)
#$(run-latex); \
PHONY: copy
copy:
cp $(TRG:%.pdf=%.pdf) $(OUTPUT_PDF_FILE_NAME).pdf
.PHONY: clean
clean:
-rm -f $(TRG) $(PSF) $(TRG:%.pdf=%.aux) $(TRG:%.pdf=%.bbl) $(TRG:%.pdf=%.blg) $(TRG:%.pdf=%.log) $(TRG:%.pdf=%.out); \
$(RM) *.toc *.lot *.lof *.log Sections/*.aux Sections/*.fls Sections/*.log Sections/*.fdb*; \
.PHONY: cleanpdf
cleanpdf:
-rm -f $(TRG) $(PSF) $(PDF) $(TRG:%.pdf=%.aux) $(TRG:%.pdf=%.bbl) $(TRG:%.pdf=%.blg) $(TRG:%.pdf=%.log) $(TRG:%.pdf=%.out); \
$(RM) *.toc *.lot *.lof Sections/*.aux Sections/*.fls Sections/*.log Sections/*.fdb*; \
$(RM) $(OUTPUT_PDF_FILE_NAME).pdf; \
.PHONY: view
view:
acroread $(TRG:%.pdf=%.pdf)
.PHONY: osx
osx:
open $(TRG:%.pdf=%.pdf)
.PHONY: count
count:
texcount main.tex
######################################################################
# Define rules for PDF source files.
.PHONY: pdf
%.pdf: %.eps
epstopdf $< > $(<:%.eps=%.pdf)
Running make, I get the error:
make: *** No rule to make target `pngfigure.pdf', needed by `main.pdf'. Stop.
If I run
$ pdflatex main.tex
It compiles fine and the images show up. The error only happens with make.
Also, as an add on to this question, in the makefile I use texcount to count the words, I couldn't figure out how to get it to load the main.tex file no matter what it was called. I had to resort to the actual filename. I think it should be something like
texcount %.tex
But that doesn't work
This error:
make: *** No rule to make target `pngfigure.pdf', needed by `main.pdf'. Stop.
means that you listed pngfigure.pdf as a prerequisite of main.pdf but that make doesn't know how to build that.
It doesn't know how to build that, presumably, because it isn't actually a pdf file (or a tex file that can be converted to a pdf file).
The incorrect prerequisite here is coming from the PDFPICS macro which is finding all the \includegraphics entries in the tex file and then spitting out $name.pdf for them. Clearly, at least in that case that is incorrect.
Additionally, simply updating the PDFPICS macro to use png instead of pdf is not enough if the images are not in the current directory (as they appear not to be in this case).
For that you'll need to incorporate parsing of \graphicspath from the document as well to include that in the PDFPICS generated prerequisites.

force a script to run at the beginning of a makefile, and display its output

I have a script which generates a version.h file with various details about the particular build
The script runs various commands, such as:
readonly VERSION=$(git describe --always --dirty --long --tags)
readonly NUM_COMMITS=$(git rev-list HEAD | wc -l | bc)
readonly BRANCH=$(git rev-parse --abbrev-ref HEAD)
readonly AHEAD_BY=$(git log --oneline origin/${BRANCH}..${BRANCH} | wc -l | bc)
readonly NUM_UNTRACKED=$(git ls-files --exclude-standard --others --full-name -- . | wc -l | bc)
readonly HOSTNAME=$(hostname)
It then writes a temporary file, checks against the pre-existing generated file, and if they are different, overwrites the old version.h with the new one.
#pragma once
/*
* Version information
*
* - This is a generated file - do not edit
*/
namespace foo { namespace app {
static const char VERSION[] = "26b75cd";
static const char NUM_COMMITS[] = "224";
static const char BRANCH[] = "master";
static const char AHEAD_BY[] = "0";
static const char NUM_UNTRACKED[] = "0";
static const char USER[] = "steve";
static const char HOSTNAME[] = "steve-linux";
static const char BUILD_VARIANT[] = "debug";
static const char BUILD_DATE[] = __DATE__ " " __TIME__;
}}
It also prints to stdout when the file is updated
version updated: 26b75cd
The version script should be the first thing that is run, and should be run every time the makefile is invoked.
Currently I achieve this by using a simply expanded variable in the makefile
new_ver := $(shell ./app/gen_version.sh $(BUILD))
It works, but any output from the script is captured in new_var, and I am unable to display that output.
It's an acceptable trade-off (not displaying the new version), but in an ideal world I would like to display the script output.
I'm unsure as to whether a .PHONY target added to the default all target will work, because every app has its own target so you can build just that.
define do-make-bin
binaries += $(addprefix $(BIN_DIR),$1)
bin_sources += $2
# a target so users can call 'make <bin-name>' and build only the bin and its dependencies
$1: $(addprefix $(BIN_DIR),$1)
# the target to build the actual binary
$(addprefix $(BIN_DIR),$1): $(call src_to_obj,$2) $(addsuffix .so,$(addprefix $(LIB_DIR)lib,$3)) $(addsuffix .a,$(addprefix $(LIB_DIR)lib,$4))
#$(CXX) $(call src_to_obj,$2) -L/usr/lib -L$(SDK_LIB_DIR) -L$(LIB_DIR) $(TARGET_LINK_FLAGS) -Wl$(,)-Bstatic $(addprefix -l,$4) $(addprefix -l,$6) -Wl$(,)-Bdynamic -Wl$(,)-rpath$(,)$(RPATH) $(linkpath) -L$(LIB_DIR) $(sdk_libs) $(tcmalloc_libs) -lpthread -lrt $(addprefix -l,$3) $(addprefix -l,$5) -rdynamic -o $$#
endef
calling make foo should still check whether version.h needs to be updated
The only way to ensure it runs before every target, if you restrict yourself to normal makefile methods, is to put the content in a recipe and then make the target that builds that content be a prerequisite of every target in your makefile. While this can be done in such a way that it doesn't cause everything to rebuild every time, it's gross. Plus, it won't let you put the output into a variable like new_ver (you say you want to display that but you don't say whether you need it in the variable as well).
However, if the only problem is that you aren't displaying the value of new_ver, that's trivially solved:
new_ver := $(shell ./app/gen_version.sh $(BUILD))
$(info $(new_ver))
When a target has no prerequisites and exists as file nothing happens. What you need is to make a conditional prerequisite when temporary file is created. You can use wildcard function of gnu/make.
If temporary file is called version.new.h and supposing that the script does the check of differences between version.h and version.new.h. If they are the same it deletes it. Then you can use something like:
version.h : $(wildcard version.new.h)
mv -f version.new.h version.h
In order to verify that version.h is created first you should split the jobs.
Then you secure that first job runs first. A sample of the Makefile code is:
all: version_h other_staff
.PHONY: version_h
version_h:
./app/gen_version.sh $(BUILD)
$(MAKE) version.h
version.h : $(wildcard version.new.h)
mv -f version.new.h version.h
other_staff: $(EXE) $(LIBS)

In Kernel makefile $(call cmd, tags) what is the cmd here refers to?

In Kernel Makefile i found the code like below:
ctags CTAGS CSCOPE: $(HEADERS) $(SOURCES)
$(ETAGS) $(ETAGSFALGS) $(HEADERS) $(SOURCES)
$(call cmd, ctags)
Also, where can i find the Macro or function ?
Using MadScientist's method on kernel v4.1:
make -p | grep -B1 -E '^cmd '
we find:
# makefile (from `scripts/Kbuild.include', line 211)
cmd = #$(echo-cmd) $(cmd_$(1))
scripts/Kbuild.include is included on the top level Makefile. It also contains:
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
quiet: set at the top level makefile, depending on the value of V.
Will be either:
quiet_ to print CC file.c
empty to print the command on V=
silent_ to not print anything on make -s
escsq is defined as:
squote := '
escsq = $(subst $(squote),'\$(squote)',$1)
It escapes single quotes so that echo '$(call escsq,Letter 'a'.' will print properly in sh.
echo-why: defined further down at Kbuild.include.
It is used for make V=2, and says why a target is being remade.
The setup of make tags is done in the Makefile:
quiet_cmd_tags = GEN $#
cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $#
tags TAGS cscope gtags: FORCE
$(call cmd,tags)
Which shows the typical usage pattern for calling commands on kbuild:
quiet_cmd_XXX = NAME $#
cmd_XXX = actual-command $#
target: prerequisites
$(call cmd,tags)
A comment on the Makefile explains how all of this is done to make the make output prettier:
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
# that echo $($(quiet)$(cmd)), we now have the possibility to set
# $(quiet) to choose other forms of output instead, e.g.
#
# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$#
# cmd_cc_o_c = $(CC) $(c_flags) -c -o $# $<
If you run make -p it will print the entire database of all variables, rules, etc. with line numbers where they were last defined.

Resources