Why $$PWD instead of $PWD in TI x-loader makefile for omap devices - linux

I started to analyse the TI X-Loader, including it's makefiles. I found the following lines in the top makefile:
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
and
ifeq (include/config.mk,$(wildcard include/config.mk))
...
Regarding the first line: i know that "$PWD" means the value of PWD (the working directory)
My question:
why the double dollar sign in this special case?
Regarding the second line: I'm trying to understand what is compared and why.
I already red the GNU MAKE manual wildcard explanation. I'm still missing something.
My questions:
what is the "$(wildcard" for?
Which config.mk files exactly are compared to each other?
Why are they compared? (this question is more about the makefile structure)
Thanks for your help in advance.
Martin

In make, you escape a dollar sign (so that it's not expanded by make) using two dollar signs ($$). So, if you write $PWD then make will interpret the $P as a make variable reference, which is likely not set and so empty, and the result (passed to the shell) will be WD. If you use $$PWD then the dollar sign is escaped and the result passed to the shell command will be $PWD which is what you want.
For the second line, the wildcard function will, among other things, expand to the empty string if there are no files that match the wildcard. So this invocation of wildcard is testing to see if the file include/config.mk exists or not. If it does, then the result of the function will be include/config.mk and the ifeq test will be true. If it doesn't then the result will be the empty string and the ifeq test will be false.
Nothing here is comparing the contents or timestamps or anything else of include/config.mk. This is purely a "does this file exist?" test.

Related

How do I write a file path which include a regular expression

Depending on the system I am working on, there might be 2 different possible paths (mutually exclusive):
System1: /tmp/aword/foo
System2: /tmp/bword/foo
I am supposed to echo something into the foo file regardless of which system I encounter (through a shell script).
How do I include a regular expression within the path itself, to take the correct (existent) path?
somethings I have tried:
#doesn't work
echo Hello > /tmp/(a|b)word/foo
#doesn't work
echo Hello > /tmp/[a|b]word/foo
is there a way of doing this without having to include a test before this which tests for path existence?
If it literally is aword and bword and you know that only one of them exists, you can use
echo 'Hello' > /tmp/[ab]word/foo
This is a shell pattern and documented in the Bash manual or the POSIX sh spec.
If, however, both paths exist, Bash will complain with
-bash: [ab]word: ambiguous redirect

How to let MAKEFILE retain the backslash sequences within a string when used in a make rule?

This is my first question on Stackoverflow so forgive me if I ask anything ridiculous :D.
Problem:
Suppose I want to compile a program that is in the directory "my dir/" with a space in it. Say the pathname of the program is "my dir/test.c".
Here is the sample makefile that I was trying out:
CC = gcc
DIR = my\ dir
$(DIR)/test.out: $(DIR)/test.c
# $(CC) $< -o $#
$(CC) $(DIR)/test.c -o $(DIR)/test.out
As you can see that in the last line(line-5) I have written the pathnames of the source and the output files directly as written in the prerequisite and the target, respectively. Doing this works fine because it yields the command:gcc my\ dir/test.c -o my\ dir/test.outwhich a syntactically correct way of passing filenames(with spaces) to gcc or any other shell command.
The second last line(line-4) is where the problem is(commented line). I've used automatic variables $# (Target) and $< (First and the only Prerequisite) to produce the filename arguments for gcc which I expected to bemy\ dir/test.out and my\ dir/test.c, respectively. But here, for some reason, the produced filenames are my dir/test.out and my dir/test.c and hence the yielded command is: gcc my dir/test.c -o my dir/test.out
Now here, gcc considers my and dir/test.c as different two different input filenames and the command generates errors.
Here is a screenshot of the generated error output when I uncomment line-4 and comment line-5 of the above Makefile:
My Question:
Is there any way to retain those backslashes even by using automatic variables the way I did? Or is there any alternative that will achieve the same goal as using automatic variables and also solve my problem? Because flexibility is important here.
Thanks in advance for your help!!!
Use double or single quotes for the automatic variables.
Use single quotes, if you want to avoid shell expansion of the values referenced by the automatic variables:
$(DIR)/test.out: $(DIR)/test.c
$(CC) '$<' -o '$#'
Double quotes allow shell expansion. For example, if there was a dollar sign in DIR:
DIR := $$my\ dir
then "$#" would expand to "$my dir", and the shell would interpret $my as variable.

"read" command not executing in "while read line" loop [duplicate]

This question already has answers here:
Read user input inside a loop
(6 answers)
Closed 5 years ago.
First post here! I really need help on this one, I looked the issue on google, but can't manage to find an useful answer for me. So here's the problem.
I'm having fun coding some like of a framework in bash. Everyone can create their own module and add it to the framework. BUT. To know what arguments the script require, I created an "args.conf" file that must be in every module, that kinda looks like this:
LHOST;true;The IP the remote payload will connect to.
LPORT;true;The port the remote payload will connect to.
The first column is the argument name, the second defines if it's required or not, the third is the description. Anyway, long story short, the framework is supposed to read the args.conf file line by line to ask the user a value for every argument. Here's the piece of code:
info "Reading module $name argument list..."
while read line; do
echo $line > line.tmp
arg=`cut -d ";" -f 1 line.tmp`
requ=`cut -d ";" -f 2 line.tmp`
if [ $requ = "true" ]; then
echo "[This argument is required]"
else
echo "[This argument isn't required, leave a blank space if you don't wan't to use it]"
fi
read -p " $arg=" answer
echo $answer >> arglist.tmp
done < modules/$name/args.conf
tr '\n' ' ' < arglist.tmp > argline.tmp
argline=`cat argline.tmp`
info "Launching module $name..."
cd modules/$name
$interpreter $file $argline
cd ../..
rm arglist.tmp
rm argline.tmp
rm line.tmp
succes "Module $name execution completed."
As you can see, it's supposed to ask the user a value for every argument... But:
1) The read command seems to not be executing. It just skips it, and the argument has no value
2) Despite the fact that the args.conf file contains 3 lines, the loops seems to be executing just a single time. All I see on the screen is "[This argument is required]" just one time, and the module justs launch (and crashes because it has not the required arguments...).
Really don't know what to do, here... I hope someone here have an answer ^^'.
Thanks in advance!
(and sorry for eventual mistakes, I'm french)
Alpha.
As #that other guy pointed out in a comment, the problem is that all of the read commands in the loop are reading from the args.conf file, not the user. The way I'd handle this is by redirecting the conf file over a different file descriptor than stdin (fd #0); I like to use fd #3 for this:
while read -u3 line; do
...
done 3< modules/$name/args.conf
(Note: if your shell's read command doesn't understand the -u option, use read line <&3 instead.)
There are a number of other things in this script I'd recommend against:
Variable references without double-quotes around them, e.g. echo $line instead of echo "$line", and < modules/$name/args.conf instead of < "modules/$name/args.conf". Unquoted variable references get split into words (if they contain whitespace) and any wildcards that happen to match filenames will get replaced by a list of matching files. This can cause really weird and intermittent bugs. Unfortunately, your use of $argline depends on word splitting to separate multiple arguments; if you're using bash (not a generic POSIX shell) you can use arrays instead; I'll get to that.
You're using relative file paths everywhere, and cding in the script. This tends to be fragile and confusing, since file paths are different at different places in the script, and any relative paths passed in by the user will become invalid the first time the script cds somewhere else. Worse, you aren't checking for errors when you cd, so if any cd fails for any reason, then entire rest of the script will run in the wrong place and fail bizarrely. You'd be far better off figuring out where your system's root directory is (as an absolute path), then referencing everything from it (e.g. < "$module_root/modules/$name/args.conf").
Actually, you're not checking for errors anywhere. It's generally a good idea, when writing any sort of program, to try to think of what can go wrong and how your program should respond (and also to expect that things you didn't think of will also go wrong). Some people like to use set -e to make their scripts exit if any simple command fails, but this doesn't always do what you'd expect. I prefer to explicitly test the exit status of the commands in my script, with something like:
command1 || {
echo 'command1 failed!' >&2
exit 1
}
if command2; then
echo 'command2 succeeded!' >&2
else
echo 'command2 failed!' >&2
exit 1
fi
You're creating temp files in the current directory, which risks random conflicts (with other runs of the script at the same time, any files that happen to have names you're using, etc). It's better to create a temp directory at the beginning, then store everything in it (again, by absolute path):
module_tmp="$(mktemp -dt module-system)" || {
echo "Error creating temp directory" >&2
exit 1
}
...
echo "$answer" >> "$module_tmp/arglist.tmp"
(BTW, note that I'm using $() instead of backticks. They're easier to read, and don't have some subtle syntactic oddities that backticks have. I recommend switching.)
Speaking of which, you're overusing temp files; a lot of what you're doing with can be done just fine with shell variables and built-in shell features. For example, rather than reading line from the config file, then storing them in a temp file and using cut to split them into fields, you can simply echo to cut:
arg="$(echo "$line" | cut -d ";" -f 1)"
...or better yet, use read's built-in ability to split fields based on whatever IFS is set to:
while IFS=";" read -u3 arg requ description; do
(Note that since the assignment to IFS is a prefix to the read command, it only affects that one command; changing IFS globally can have weird effects, and should be avoided whenever possible.)
Similarly, storing the argument list in a file, converting newlines to spaces into another file, then reading that file... you can skip any or all of these steps. If you're using bash, store the arg list in an array:
arglist=()
while ...
arglist+=("$answer") # or ("#arg=$answer")? Not sure of your syntax.
done ...
"$module_root/modules/$name/$interpreter" "$file" "${arglist[#]}"
(That messy syntax, with the double-quotes, curly braces, square brackets, and at-sign, is the generally correct way to expand an array in bash).
If you can't count on bash extensions like arrays, you can at least do it the old messy way with a plain variable:
arglist=""
while ...
arglist="$arglist $answer" # or "$arglist $arg=$answer"? Not sure of your syntax.
done ...
"$module_root/modules/$name/$interpreter" "$file" $arglist
... but this runs the risk of arguments being word-split and/or expanded to lists of files.

How to strip sub-directories from path using shell

In a make file i want to strip some sub-directories from a path given in a variable. I figure i can use $(shell ...) to do it, so a sed one-liner or similar would do the trick i think. Any suitable make technique would do though.
The path contained in the variable typically looks like:
/repo/myrepo/products/foo/prod1/test/gtest/bin/XXX
or
/repo/myrepo/products/cool_products/bar/prod2/test/gtest/bin
And i want to strip everything after prod1 and prod2 above, giving the results:
/repo/myrepo/products/foo/prod1
/repo/myrepo/products/cool_products/bar/prod2
In other words, strip all directories starting with test/gtest which i can assume is in all the paths i will be applying this to. I have not been able to figure out a clean way to strip a different number of sub-directories.
sed 's#/test/gtest.*##g'
This will remove everything from /test/gtest to the end.
Sample:
AMD$ echo "/repo/myrepo/products/foo/prod1/test/gtest/bin/XXX" | sed 's#/test/gtest.*##g'
/repo/myrepo/products/foo/prod1
Another possibility, if you want to do it with functions internal to GNU make instead of invoking a separate program via $(shell ...), would be something like:
FULL_PATH = /repo/myrepo/products/foo/prod1/test/gtest/bin/XXX
STRIPPED_PATH := $(firstword $(subst /test/gtest, ,$(FULL_PATH)))
Basically this says "take $(FULL_PATH) and first replace the string /test/gtest with a space character everywhere it appears in the string, then return the first word of the resulting string".

Linux unexpected things with shell and cmake etc

I am facing a strange issue with cd command and cmake.
cd command is not working with the paths which contain '-' minus sign in it. (unless used by tab expansion which is not desireable as path will be provided by ENV variable)
cmake issue
export $SOME_VAR=Some_value_for_this_variable
Now using this in cmake as
set (SOME_OTHER_VAR "$ENV{SOME_VAR}/SUFFIX")
above should give the output as SOME_OTHER_VAR=Some_value_for_this_variable/SUFFIX but instead it is replacing the env variable from starting and giving the output as SOME_OTHER_VAR=SUFFIXalue_for_this_variable means Some_v is replaced from starting with SUFFIX which is not expected.
Please help as i am not getting whats happening.
You're having some sort of character set issue. There are two different minus signs. The hyphen - (ASCII 45, U+002D), and the real minus sign − (U+2212). It's possible that the filename itself got the non-ASCII minus sign, which you can't easily type with your keyboard. The easiest fix would be to rename the file to the normal hyphen. Otherwise, you have to convince CMake to understand your Unicode filename. I have no idea if that's easy or hard.
I think your second problem is similar. The environment variable likely one or more non-printing characters in it, messing up the CMake variables, or at least the display. Try this: from the Linux command prompt, inspect the actual contents of the string.
echo $SOME_VAR | od -t c
For ASCII representation of everything, and/or
echo $SOME_VAR | od -t d1
for the byte contents

Resources