Problem in Makefile - shell

I am executing the following command in Makefile:-
#ls export_mojave/marker_*.tcl > export_mojave.list
#for file in `cat export_mojave_tcl_files.list`; do \
diff $$file bk_marker > $$file.diff ; \
if ! [ -s $$file.diff ]; then\
rm -f $$file.diff ; \
else \
echo $$file >> marker.fill.tcl.diff; \
fi \
done ;
If there exists some file related to the above expression in the mentioned directory,
it will run fine but if there does not exits any files matching to above expression, It is marking an error. Is there anything exists like "catch" in Makefile?

If you need to skip error in makefiles' rule, then prefix command with '-' sign:
-#ls .... > some_file || echo Error: no file;
if [ -e some_file ] ....
Or modify to be more in make-style:
FILES := $(shell ls ...)
ifeq ($(FILES),)
$(error no files)
endif
....
target:
$(foreach file,$(FILES), ...)

Related

Makefile cache creating false positive outcome

I have a make target, which i usually need to run twice to get accurate outcome. I.e the 1st run if accurate thenn on the 2nd run, if the variable is changed, it still displays the previous output, which is wrong, is there a way to get rid of cache or clear it in between.
.PHONY:check-tf-lint
check-tf-lint: configure ## TF Linting
$(eval list_of_dir := $(shell cd ${deployment} && ls -ld */ | awk '{print $$NF}'| grep -v 'test_cases'| sed 's|/||g'))
$(shell touch ${quality-metrics}/formatting.txt)
#for i in aws_bot; do \
make set-tf-version -e infra_module_path=$$i; \
terraform fmt -check -list=false ${deployment}/$$i ; \
if [ "$$?" != "0" ]; then \
echo "Need Formatting in $$i" >> ${quality-metrics}/formatting.txt; \
terraform fmt -check ${deployment}/$$i >> ${quality-metrics}/formatting.txt; \
echo "" >> ${quality-metrics}/formatting.txt; \
fi \
done
$(eval TMP := $(shell (cat ${quality-metrics}/formatting.txt | wc -l)))
echo "${TMP}"
#if [ "$(TMP)" = "0" ]; then \
echo "All Good! No Formatting Needed."; \
else \
echo "Kindly Format Below Mentioned code and check in Again"; \
cat ${quality-metrics}/formatting.txt; \
fi
$(shell rm -rf ${quality-metrics}/formatting.txt)
#if [ "$(TMP)" != "0" ]; then \
exit 1; \
fi
Rule of thumb: you should never use eval or shell functions in a make recipe. If you are doing that it's a pretty sure sign that something has gone wrong somewhere.
In your case the reason you see this behavior is that make will expand ALL variables and functions for all lines in a recipe before the first line in the recipe is invoked. So as far as make is concerned your recipe is handled like this:
.PHONY:check-tf-lint
check-tf-lint: configure ## TF Linting
$(eval list_of_dir := $(shell cd ${deployment} && ls -ld */ | awk '{print $$NF}'| grep -v 'test_cases'| sed 's|/||g'))
$(shell touch ${quality-metrics}/formatting.txt)
$(eval TMP := $(shell (cat ${quality-metrics}/formatting.txt | wc -l)))
$(shell rm -rf ${quality-metrics}/formatting.txt)
#for i in aws_bot; do \
make set-tf-version -e infra_module_path=$$i; \
terraform fmt -check -list=false ${deployment}/$$i ; \
if [ "$$?" != "0" ]; then \
echo "Need Formatting in $$i" >> ${quality-metrics}/formatting.txt; \
terraform fmt -check ${deployment}/$$i >> ${quality-metrics}/formatting.txt; \
echo "" >> ${quality-metrics}/formatting.txt; \
fi \
done
echo "${TMP}"
#if [ "$(TMP)" = "0" ]; then \
echo "All Good! No Formatting Needed."; \
else \
echo "Kindly Format Below Mentioned code and check in Again"; \
cat ${quality-metrics}/formatting.txt; \
fi
#if [ "$(TMP)" != "0" ]; then \
exit 1; \
fi
You should always write your recipes using shell facilities and not make facilities. Set shell variables, don't use eval to set make variables, and run shell commands directly (you're in a recipe after all!) rather than using make's shell function.
You may need to put all the lines in a single script (with semicolon / backslash) to allow this to work. Or consider .ONESHELL but that's a much bigger set of changes.
This worked for me !
.PHONY:check-tf-lint
check-tf-lint: ## TF Linting
$(eval list_of_dir := $(shell cd ${deployment} && ls -ld */ | awk '{print $$NF}'| grep -v 'test_cases'| sed 's|/||g'))
#for i in $(list_of_dir); do \
make set-tf-version -e infra_module_path=$$i; \
terraform fmt -check -list=false ${deployment}/$$i ; \
if [ "$$?" != "0" ]; then \
echo "Need Formatting in $$i" >> ${quality-metrics}/formatting.txt; \
terraform fmt -check ${deployment}/$$i >> ${quality-metrics}/formatting.txt; \
echo "" >> ${quality-metrics}/formatting.txt; \
fi \
done
#if [ -e "${quality-metrics}/formatting.txt" ]; then \
export MNC=`cat ${quality-metrics}/formatting.txt | wc -l`; \
if [ "$${MNC}" = "0" ]; then \
echo "All Good! No Formatting Needed."; \
else \
echo ""; \
echo "Kindly Format Below Mentioned code and check in Again"; \
cat ${quality-metrics}/formatting.txt; \
fi; \
rm -rf ${quality-metrics}/formatting.txt; \
if [ "$${MNC}" != "0" ]; then \
exit 1; \
fi \
fi

how to use if statement from a makefile function?

I am reading configurations from .config file and I want to do some operation if a configuration is enabled. I have written following function but it is throwing error message "/bin/sh: 1: Syntax error: ")" unexpected (expecting "then")"
define parse_configs
while read -r file; do \
config=$$(echo $$file | grep -Po '(?<=(CONFIG_)).*(?==)'); \
val=$$(echo $$file | grep -Po '(?<=(=)).*'); \
$$(if $(findstring y, $$val), echo "do Ops", echo "No ops"); \
done < .config;
endef
The problem is with if statement, other part of function is fine. Please let me know the mistake in the code. Thanks.
What is wrong with the statement:
$$(if $(findstring y, $$val), echo "do Ops", echo "No ops");
is that is actually a GNU Make if-function,
calling the GNU Make findstring-function,
which you have written in the middle of a shell statement, and required ($$) that it be expanded by the shell, but it makes no sense to the shell.
It might as well be Javascript. Replace it with an appropriate shell if-statement, e.g.
while read -r file; do \
config=$$(echo $$file | grep -Po '(?<=(CONFIG_)).*(?==)'); \
val=$$(echo $$file | grep -Po '(?<=(=)).*'); \
if [ -z $${val##*"y"*} ]; then echo "do Ops"; else echo "No ops"; fi; \
done < .config;

makefile giving unexpected end of file error

HOMEDIR = $(shell pwd)
DEFAULT = 4.0.3
YESDIR = $(shell echo $(#:install-%=%) | tr A-Z a-z)
NODIR = $(shell echo $(#:clean-%=%) | tr A-Z a-z)
install:
#$(MAKE) install-$(DEFAULT)
install-%:
#cd $(HOMEDIR);\
if [ ! -e $(YESDIR) ]; then \
echo "Library $(#:install-%=%) Version=$(YESDIR) does not exist"; \
elif [ -e $(YESDIR)/Install.sh ]; then \
echo "Installing $(PKGNAM) version=$(YESDIR)" ; \
cd $(YESDIR) ;\
$(SHELL) Install.sh $(HOMEDIR) 1 ;\
elif [ -e $(YESDIR)/Makefile ]; then \
cd $(YESDIR); \
$(MAKE); \
else \
echo "Installation instruction for $(#:install-%=%) Version=$(YESDIR) does not exist"; \
fi;
the above makefile gives me the following error
line 6: syntax error: unexpected end of file
Remove trailing blanks in this line:
$(SHELL) Install.sh $(HOMEDIR) 1 ;\

Makefile: make text file and append strings in it

I'm having difficulties with makefiles.
So in a recipe, I'm making a file (with a name and a .ujc extension) in a for loop and would like to have a text file at the end which contains all the created files. Purpose is to feed it to an application.
For example, in a semi high-level example,
List= [Class1,Class2,Class3]
foreach(Class C in List) {
#do operations on C > outputs a ClassX.ujc file
# add name of file to a text file named "list_of_files"
}
At the end I should have a text file, list_of_files.txt, which contains the following string:
Class1.ujc Class2.ujc Class3.ujc
As a reference, the code I have at the moment (and which does a bit of the stuff above but does not work is) is:
pc: $(APP)
$(foreach C, $(shell echo $(CLASS) | tr ',' ' '), \
make -C BUILDENV CLASS=$(C) BUILD=just_filelist OUTPUT=filelist.txt SKIPSELF=yes && \
../classCvt/classCvt <./Applications/$(C).class> ./Applications/$(C).ujc && \
cat app_file_list.txt | xargs echo ./Applications/$(C).ujc >app_file_list.txt && \
) true
time -p ./$(APP) `cat app_file_list.txt` `cat filelist.txt`
The internal make does make a filelist which is fed to the app, but I'd also like to feed the app_file_list but its construction goes totally wrong.
Probably simple, but I'm not getting there.
Edit:
The code below does what I want:
pc: $(APP)
rm -f cat app_file_list.txt
$(foreach C, $(shell echo $(CLASS) | tr ',' ' '), \
make -C BUILDENV CLASS=$(C) BUILD=just_filelist OUTPUT=filelist.txt SKIPSELF=yes && \
../classCvt/classCvt <./Applications/$(C).class> ./Applications/$(C).ujc && \
cat app_file_list.txt | echo ./Applications/$(C).ujc >>app_file_list.txt && \
) true
time -p ./$(APP) `cat app_file_list.txt` `cat filelist.txt`
Notable mistake I made was the xargs.
(Also in the post)
The solution turned out to be not-so-difficult. I needed to remove the xargs command and do the correct operation (i.e., >> instead of >) in the 'cat app_file_list.txt | etc...' line.
The code below does what I want:
pc: $(APP)
rm -f cat app_file_list.txt
$(foreach C, $(shell echo $(CLASS) | tr ',' ' '), \
make -C BUILDENV CLASS=$(C) BUILD=just_filelist OUTPUT=filelist.txt SKIPSELF=yes && \
../classCvt/classCvt <./Applications/$(C).class> ./Applications/$(C).ujc && \
cat app_file_list.txt | echo ./Applications/$(C).ujc >>app_file_list.txt && \
) true
time -p ./$(APP) `cat app_file_list.txt` `cat filelist.txt`
Notable mistake I made was the xargs which caused strings to repeat into the .txt file.

Unix shell bash script unable to put an echo debug statement

I have the following make file, which i think is a shell script.
I am trying to loop through FILE_DIR to perform some operations. However, i feel that the implementation isn't working as expected. So i am trying to insert some echo breakpoints.
Source:
# Target to recurse through the DIR_LIST and make each makefile found in that DIRS
ALLDIRS:
for se in $(FILE_DIR); do \
if [ -d $se ]; then \
cd $se; \
$(MAKE) -f Makefile.mk all; \
cd ..; \
fi \
done
Running:
$ make -f Makefile.batch
h: syntax error at line 3: `then' unexpected
*** Error code 2
The following command caused the error:
for se in `ls -p /app/internal|grep "/"`; do \
echo "Test" \
if [ -d e ]; then \
cd e; \
/usr/ccs/bin/make -f Makefile.mk all; \
cd ..; \
fi \
done
make: Fatal error: Command failed for target `ALLDIRS'
Can i please get help on this. Would like to insert an echo breakpoint.
One common error in Makefiles is using spaces instead of tabs in a command line. Check the whole for loop and make sure there are only tabs at the beginning of each line
ALLDIRS:
<tab>for se in $(FILE_DIR); do \
<tab><tab>if [ -d $se ]; then \
<tab><tab>cd $se; \
<tab><tab>$(MAKE) -f Makefile.mk all; \
<tab><tab>cd ..; \
<tab><tab>fi \
<tab>done
Another error is the dollar sign $. If you want a dollar sign in the shell command, you must double it in your commands, because otherwise dollar introduces a make variable and will be expanded before the shell sees it.
for se in $(FILE_DIR); do \
if [ -d $$se ]; then \
cd $$se; \
$(MAKE) -f Makefile.mk all; \
cd ..; \
fi \
done
And the final one, echo Test needs a semicolon as well
for se in $(FILE_DIR); do \
if [ -d $$se ]; then \
echo "Test"; \
cd $$se; \
...

Resources