Overriding make variables containing spaces with MAKEFLAGS - bash

I have a bash script to run my Makefile-based project through Include-What-You-Use (IWYU) which looks as follows:
#!/bin/bash
export MAKEFLAGS="-k CXX=iwyu -Xiwyu --transitive_includes_only -Xiwyu --mapping_file=qt5_4.imp"
build.sh
The build.sh script sets a couple of environment variables, prepares other parts of the build environment and will then eventually run make.
At first sight this seems to work and do its job. However closer inspection showed, that only CXX=iwyu is actually used in the build. The command line options for IWYU get dropped.
I tried various modifications of my call to fix this, however none seemed to solve the problem.
With
export MAKEFLAGS="-k CXX=iwyu\ -Xiwyu\ --transitive_includes_only\ -Xiwyu\ --mapping_file=qt5_4.imp"
the command line options are no longer dropped, but now suddenly -k seems to get dropped somewhere and my build (because of the missing -k) is terminated early with failure.
With
export MAKEFLAGS="-k CXX='iwyu -Xiwyu --transitive_includes_only -Xiwyu --mapping_file=qt5_4.imp'"
I'm flooded with /bin/sh: 1: Syntax error: Unterminated quoted string which looks like the ending ' is somehow dropped.
Are there any other ways I have to escape and/or quote the spaces in my export to fix this?

You can create a script (once?) to run iwyu — be careful, single quotes and double quotes are not interchangeable:
echo 'iwyu -Xiwyu --transitive_includes_only -Xiwyu --mapping_file=qt5_4.imp "$#"' > ./run.iwyu
chmod +x ./run.iwyu
and then run:
make -k CXX="$PWD/run.iwyu"
or:
export MAKEFLAGS="-k CXX=$PWD/run.iwyu"
This sidesteps the whole problem of spaces in the arguments. As shown, you specify the full path for the run.iwyu script just in case your make process changes directories. If you put the run.iwyu script in a directory on your PATH, you don't need to specify the full path to the script. You could prefix the command line in the script with exec if you like.

Related

How to run shell script by including "cd" command in ubuntu?

I am trying to execute a shell script for automating the process rather than manually running the python script. But i am getting the error folder not found.
cd /home/gaurav/AndroPyTool
export ANDROID_HOME=$HOME/android-sdk-linux/
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools
source ~/.bashrc
source droidbox_env/bin/activate
alias mycd='cd /home/gaurav/AndroPyTool/test'
mycd
pwd
python androPyTool.py -all -csv EXPORTCSV.csv -s mycd
>>>> AndroPyTool -- STEP 1: Filtering apks
Folder not found!
This is the error i am getting because the script is not able to find the path that i have provided above.
The part after "-s" in the code represents the folder path where the file stored.
The issue here is that you are not passing the path to the python program. The python program is not aware of bash aliases and bash will only expand aliases when it is interpreting the token as a command.
When bash reads python androPyTool.py -all -csv EXPORTCSV.csv -s mycd It interprets python as the command and all other space separated tokens are arguments that will be passed into python. Python then invokes androPyTool.py and passes the subsequent arguments to that script. So the program is receiving literally mycd as the argument for -s.
Moreover, even if mycd is expanded, it wouldn't be the correct argument for -s. androPyTool.py is expecting just the /path/to/apks, not cd /path/to/apks/.
I don't really think that using the alias in this script makes much sense. It actually makes the script harder to read and understand. If you want to wrap a command, I recommend defining a function, and occasionally you can use variable expansion (but that mixes code and data which can lead to issues). EDIT: As has been pointed out in the comments, aliases are disabled for scripts.
Finally there are some other suspicious issues with your script. Mainly, why are you sourcing .bashrc? If this script is run by you in your user's environment, .bashrc will already be sourced and there is no need to re-source it. On the other hand, if this is not intended to be run in your environment, and there is something in the .bashrc file that you need in your script, I recommend pulling just that out and nothing else.
But the most immediate issue that I can see is that sourcing .bashrc after you modify path runs the risk of overwriting the changes to PATH you just made. Depending on the contents of the .bashrc file, sourcing it may not be idempotent, meaning that running it more than once could have side effects. Finally, anything could get thrown in that .bashrc file down the road since that's what its for. So now your script may depend on something that likely will be changing. This opens up the possibility that bugs will creep in to your script unexpectedly.

Makefile ifeq fails

I'm new to makefile and find using findstring rather hard.
Here's my code:
ZSHRC="$HOME/.zshrc"
install:
ifneq($(findstring "CADANSE",$(ZSHRC) a),)
#echo "done $(a)"
endif
Wherever I move the comma I get errors, most frequently:
syntax error near unexpected token `,'
I made sure my tabs are 4 proper spaces and tried a couple of tutorials to get it working but to no avail.
I need to check if the string BEGIN.CADANSE is in .zshrc because it loads extra shell methods. I'm trying to make an installer for it, makefile is not mandatory but I've been required to investigate it.
Thank you for any help.
OS is latest MacOSX and shell is oh-my-zsh.
UPDATE - Solution
To address my issue I'm going through a patch now, instead of a grep:
installcadanse: docs
#cat ~/.zshrc lib/Cadanse/template/dot-rc | diff -u ~/.zshrc - > PATCH_CADANSE ; patch ~/.zshrc PATCH_CADANSE
#source ~/.zshrc ; echo "Cadanse should be installed in your shell. Please check ~/.zshrc for mentions of Cadanse."
Zeroth of all, what do you mean by "my tabs are 4 proper spaces"? The action part of a rule must be indented by a tab. Not 4 spaces, not 8 spaces, but a literal tab character.
First, the commands associated with a rule are passed to the shell (after variable expansion). If you want to test a condition in an action, you have to write a shell command for it, not a make command.
Second, findstring performs a simple substring search. It does not open any files or read their contents.
Third, I'm pretty sure "$HOME/.zshrc" in make means "${H}OME/.zshrc" (i.e. it'll look for a variable called H). Also, those quotes are taken literally.
To search a file for a given string in a shell script, you can use grep:
.PHONY: install
install:
#if grep -q CADANSE ~/.zshrc; then \
echo done; \
fi

How to determine which scripts in my ~/Shell directory are causing my ~/.zshrc file to take so long to be loaded?

I have a ~/.zshrc file that executes all the top-level shell scripts in my ~/Shell directory, these top-level scripts in turn execute the lower-level scripts. For example, scripts in ~/Shell/programs (the so called "lower-level scripts") are executed by the top-level ~/Shell/09-programs.sh script. I have noticed lately that running ~/.zshrc has become much slower than it used to be and I would like to know if there are any methods to determine which script (or set of scripts) in my ~/Shell directory are causing it to become so slow. It would also be helpful to know the precise line number in each script that causes the script to become so slow. If you would like to see my ~/.zshrc file and ~/Shell scripts here is their GitHub repository that I update regularly.
PS4=':[%*]:%x:%I+' zsh -x -l -i
will run a new login shell with each line executed preceded by a second-accurate timestamp, the filename and line number from which it was defined.
Incidentally, the bash equivalent to this looks something like:
PS4=':[\t]:$BASH_SOURCE:$LINENO+' bash -x -l -i
...though personally, I might use $SECONDS in that case rather than \t, to get an integer number of seconds since shell invocation.

export environment variable from a makefile to the system

For one of my project, I need to add something to an env var from a makefile.
Here's a the sandboxed problem :
First, the makefile
all:
$(shell source <(echo export MYVAR=$(MYVAR):otherstuff))
And what I'm trying to achieve
export MYVAR=stuff
make
echo $MYVAR
So technically, MYVAR should contains stuff:otherstuff. But instead of that I got a bash error
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `source <(echo export MYVAR=$MYVAR:otherstuff)'
I don't know what I did wrong, the command worked outside of the makefile.
Thanks!
And what I'm trying to achieve
export MYVAR=stuff
make
echo $MYVAR
So technically, MYVAR should contains stuff:otherstuff.
As was mentioned in the comments, you can't do it. A copy of environment is inherited from the parent process (the shell where you perform export MYVAR=stuff) by the child process (the make call), and whatever the child process does with the variable, would be visible to the make itself, or its own child processes. But never the parent.
Generally, when I need to export some information from the Makefile, I provision special targets for the purpose, e.g.:
print-env:
#echo export MYVAR=$(MYVAR):otherstuff ";"
#echo export MYOTHERVAR=helloworld ";"
Now when you do make print-env, it would produce the output like this:
export MYVAR=stuff:otherstuff ;
export MYOTHERVAR=helloworld ;
Using the makefile we have generated commands, which could be easily copy-pasted from the output into command prompt to execute them.
Though it is possible and doable, I would advise against the feeding of make's output to the shell directly:
eval "`make print-env`"
or even more radical:
`make print-env`
since make output is generally unstable, and might accidentally contain output of other rules, which might confuse the shell.

Why Does this sed command work in terminal but not in bash ".sh" script

Sorry this seems to be asked a lot in various different ways but none have helped me understand why this isn't working.
If I run the following:
sed -i".bak" "s:$PRELOADER_BASH::" ~/.bashrc
in the terminal, it works. However I want to run it as part of a sh script, when I do this I get the following error:
sed: -e expression #1, char 8: unterminated `s' command
Can someone please explain to me why it is doing this?
Environment variable PRELOADER_BASH is:
export LD_PRELOAD=/usr/lib/mylib1.so /usr/lib/mylib2.so
The spaces and slashes caused me early problems.
Your variable PRELOADER_BASH is known to the shell script? You have to export it to have access to it in sub shells (e.g. in shell scripts).
Define your variable like that:
export PRELOADER_BASH="export LD_PRELOAD=/usr/lib/mylib1.so /usr/lib/mylib2.so"
Then run your shell script and it will work. It will replace all occurences of export LD_PRELOAD=/usr/lib/mylib1.so /usr/lib/mylib2.so in your ~/.bashrc file with nothing (i.e. delete it).
Explanation
On the command line you had probably defined your variable like that:
PRELOADER_BASH="export LD_PRELOAD=/usr/lib/mylib1.so /usr/lib/mylib2.so"
This makes it available in the current shell, but not in sub shells. Therefore you need to use export.
Instead of exporting you can also define your variable in the shell script.
Ok so it turns out i was being a bit over cautious and silly as i didnt post the exact script code here, earlier on in the bash files life cycle when trying to solve the spaces and /'s issue I was exporting PRELOADER_BASH in the following way:
PRELOADER_BASH='export LD_PRELOAD="/usr/lib/libopenvg.so /usr/lib/libinterposer.so"'
which is actually what caused the error! the best way was to do the following:
PRELOADER_BASH="export LD_PRELOAD=/usr/lib/libopenvg.so /usr/lib/libinterposer.so"
in hindsight its really stupid because with my "over-done" preloader bash setting it was probably expanding it directly to:
sed -i".bak" "s:'export LD_PRELOAD="/usr/lib/libopenvg.so /usr/lib/libinterposer.so"'::" ~/.bashrc
so the sed command would have indeed have a " unterminated `s' command "
sed -i".bak" " s:'export LD_PRELOAD="/usr/lib/libopenvg.so /usr/lib/libinterposer.so "'::" ~/.bashrc
very sorry to waste peoples time on this, clearly I need a cup of coffee!

Resources