I have a problem while programming with using shell in makefile - shell

the code is:
# android/device/mediatek/build/core/build_dtboimage.mk
...
my_dtbo_id := 0
define mk_dtboimg_cfg
$(eval name := $$(basename $1)) \
echo "file name:$(name)"; \
$(eval dts_file_name := $(notdir $(name))) \
echo "terminal_name:$$(echo $(dts_file_name) | awk -F '_' '{print $$1}')"; \
$(eval terminal_name := $$(echo $(dts_file_name) | awk -F '_' '{print $$1}')) \
$(eval main_name := $$(echo $(dts_file_name) | awk -F '_' '{print $$3}')) \
echo "terminal_name :$(terminal_name), main_name :$(main_name )"; \
...
and the output is:
file name:out/target/product/k62v1_64_pax/obj/KERNEL_OBJ/arch/arm64/boot/dts/mediatek/A3700_MT6762_V02_V01
terminal_name:A3700
terminal_name:, main_name:
As shown above, the code echo "terminal_name:$$(echo $(dts_file_name) | awk -F '_' '{print $$1}')"; \ can get the right output of A3700, but i don't know why the output of terminal_name and main_name is null.
the right output i expect is terminal_name:A3700, main_name:V02, in other words, i hope terminal_name and main_name can correctly assigned.
What should I do to solve this problem?
thanks!

You're making this far too complicated.
Remove the unnecessary functions and be generous with $:
...
dts_file_name := $$(notdir $$(name))
terminal_name := $$(shell echo $$(dts_file_name) | awk -F '_' '{print $$$$1}')
main_name := $$(shell echo $$(dts_file_name) | awk -F '_' '{print $$$$3}')
$$(info terminal: $$(terminal_name), main: $$(main_name))
...

Related

How to properly write for loop in Makefile

I went through some posts, but still didn't get how it work.
My request is:
for i in *.json
do
file = `echo $i |cut -d _ -f2`
echo ${file}
# do the rest tasks
done
How to convert above script to target of Makefile?
Here is what I tried
foo:
for i in *.json; do \
$(eval FILE = $(shell echo $$i |cut -d _ -f2)); \
echo $(FILE) ;\
done
But it doesn't work
Using $(eval) or $(shell) is ... not even wrong.
foo:
for i in *.json; do \
file=$$(echo "$$i" |cut -d _ -f2); \
echo "$$file"; \
done
Notice the quoting of the filename variables, and the absence of spaces around the = assignment operator, and the doubling of any dollar sign in order to pass it through from make to the shell.
However, the shell provides a much better mechanism for this;
foo:
for i in *.json; do \
j=$${i#*_}; \
echo "$${j%%_*}"; \
done
or perhaps
foo:
printf '%s\n' *.json \
| sed 's/[^_]*_\([^_]*\)_.*/\1/'
If you only expect a single underscore, both of these can be further simplified.
Or maybe you are just looking for
makefile_variable := $(foreach x,$(wildcard *.json),$(word 2,$(subst _, ,$x)))

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.

Using shell in Makefile to find Ubuntu Version

I'm trying make Ubuntu version specific distros of my tool so I want to get the os name and version. I have the following code:
ifeq ($(OS),Windows_NT)
OS_POD+=win
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
OS_VERS := $(shell lsb_release -a 2>/dev/null | grep Description | awk '{ print $2 "-" $3 }')
OS_POD=./dist/linux/$(OS_VERS)
endif
ifeq ($(UNAME_S),Darwin)
OS_POD=./dist/mac
endif
endif
I use the shell one-liner:
lsb_release -a 2>/dev/null | grep Description | awk '{ print $2 "-" $3 }'
Which properly returns Ubuntu-12.04.2 outside of the Makefile, but inside it it returns nothing. That is, the OS_VERS variable is just -.
How can I fix this?
In a Makefile, $ is special. Use $$ where you want the shell to find a dollar.
OS_VERS := $(shell lsb_release -a 2>/dev/null | grep Description | awk '{ print $$2 "-" $$3 }')
You need to escape the $ inside your command.
OS_VERS:=$(shell lsb_release -a 2>/dev/null | grep Description | awk '{ print $$2 "-" $$3 }')
The following sample Makefile prints correctly so it may be a different part of your Makefile.
print:
#echo $(OS_VERS)
OS_VERS:=$(shell lsb_release -a 2>/dev/null | grep Description | awk '{ print $$2 "-" $$3 }')
OS_VERS := $(shell cat /etc/os-release | grep ^NAME | cut -d'=' -f2 | sed 's/\"//gI')

Shell script for running g++

I don't know too much about scripts but I need a script that will run this command:
g++ -O0 -c fileName.cpp && nm fileName.o | egrep ' [A-Z] ' | egrep -v ' [UTV] ' | grep -v .eh > fileName.txt
for files with names 000000 - 008577. So how should my script be written?
UPD2:
I've written a script and it works:
#!/bin/bash
s1="g++ -O0 -c "
s2=".cpp && nm "
s3=".o | egrep ' [A-Z] ' | egrep -v ' [UTV] ' | grep -v .eh >> "
s4=".txt"
for ((i=0; i<=8577; i++)) do
num="$( printf '%06d' ${i})"
s="${s1}${num}${s2}${num}${s3}${num}${s4}"
eval $s
done
Try removing the spaces around the equal sign when you get to num and s.
I've written working code:
#!/bin/bash
s1="g++ -O0 -c "
s2=".cpp && nm "
s3=".o | egrep ' [A-Z] ' | egrep -v ' [UTV] ' | grep -v .eh >> "
s4=".txt"
for ((i=0; i<=8577; i++)) do
num="$( printf '%06d' ${i})"
s="${s1}${num}${s2}${num}${s3}${num}${s4}"
eval $s
done

bash command substitution force to foreground

I have this:
echo -e "\n\n"
find /home/*/var/*/logs/ \
-name transfer.log \
-exec awk -v SUM=0 '$0 {SUM+=1} END {print "{} " SUM}' {} \; \
> >( sed '/\b0\b/d' \
| awk ' BEGIN {printf "\t\t\tTRANSFER LOG\t\t\t\t\t#OF HITS\n"}
{printf "%-72s %-s\n", $1, $2}
' \
| (read -r; printf "%s\n" "$REPLY"; sort -nr -k2)
)
echo -e "\n\n"
When run on a machine with bash 4.1.2 always returns correctly except I get all 4 of my new lines at the top.
When run on a machine with bash 3.00.15 it gives all 4 of my new lines at the top, returns the prompt in the middle of the output, and never completes just hangs.
I would really like to fix this for both versions as we have a lot of machines running both.
Why make life so difficult and unintelligible? Why not simplify?
TXFRLOG=$(find /home..... transfer.log)
awk .... ${TXFRLOG}
The answer I found was to use a while read
echo -e "\n\n"; \
printf "\t\t\tTRANSFER LOG\t\t\t\t\t#OF HITS\n"; \
while read -r line; \
do echo "$line" |sed '/\b0\b/d' | awk '{printf "%-72s %-s\n", $1, $2}'; \
done < <(find /home/*/var/*/logs/ -name transfer.log -exec awk -v SUM=0 '$0 {SUM+=1} END{print "{} " SUM}' {} \;;) \
|sort -nr -k2; \
echo -e "\n\n"

Resources