Running a script inside a makefile - shell

I want to run a script inside a makefile like this
all: a b
a:
cd ~/trials; \
. ./sx.sh
b:
echo $(bn)
sx.sh do this
export bn=1
I don't see the variable in my terminal while issuing make command. My aim is to run a script before compiling my project for those script specific settings.

You can't assume that the commands issued by make are all processed by the same instantiation of the shell. Make does not open a shell and feed it commands one-by-one and nor does it save the commands into a file and then feed it into a shell. It usually spawns a shell for each command like this:
$(SHELL) -c 'cd ~/trials; . ./sx.sh'
which means you cannot alter the environment and have it inherited by later commands.
The best way is to use make variables to store the specifics you wish to pass to the commands and use those variables in appropriate places.

Related

Makefile to add shell aliases

I am already using a makefile, and I was hoping to be able to use it to store a few useful aliases that the user could then invoke. I know that I can make a bash file with the aliases already built in, so and run it with source, so I can do something like:
# File: aliases.sh
alias useful="command to run"
alias also-useful="another command -to run"
Then I can run this in the current terminal session with:
source ./aliases.sh
Using a Makefile
So I was hoping to achieve something similar with a makefile, I was hoping to have a simple aliases entry, so the user could just run:
make aliases
I prefer to avoid adding an extra file if this is at all possible, because I don't want to add extra files for such simple tasks. If you have any suggestions that would be better, I'd be open to hearing them too.
If what you're asking is for make aliases to create aliases that you can then invoke at your shell prompt, something like:
$ make aliases
$ useful
then that is impossible and the reason has nothing to do with make.
In a UNIX/POSIX system the process hierarchy is strict: a process starts one or more sub-processes, and each of those can start more, etc. So a login manager process starts your shell (or your window manager), your shell starts make, which is another process, and make will run another shell as a subprocess to run each recipe, and each shell will run programs like compilers, commands like rm which are also processes, etc.
It is a fundamental rule of all processes that they cannot modify the environment (memory) of their parents (and they can only modify the environment of their children before they are started). So, if you start a new shell and change your working directory then exit that shell, the parent's shell is not changed. If you set an environment variable in the child process, the variable is not set in the parent. Etc.
Shell aliases are part of a particular shell's memory. So a program you start cannot create aliases in its parent shell. It doesn't matter if that program is make or anything else.
That's why you have to use the special command source to load those into your shell: instead of running a new shell, the source command tells the current shell to run the commands in the script as if you'd typed them in at the command line... so no new process is created and the current shell's environment and memory is modified. If you ran your aliases file as a shell script, via aliases rather than source aliases, then a new shell would be created, the aliases would be defined, then the shell would exit and all the aliases would be gone again.
So, all that to say it's not possible for make to define aliases in the shell that invokes it: the operating system won't allow it.

Export variable declared in script.sh and Import the value in mupltiple Makefiles

I am trying to create something like a global variable that I will use in order to make my project easy to deploy for other developers.
I would like to have an .sh file where there is a variable defining the location of the project.
Later on I want to export this variable and make it accessable in every makefile that I am creating so that I can use this design to keep everything constant and in one place.
This is an example of what I am trying to build:
Creating and exporting the variables in script.sh:
#!/bin/bash
DIRECTORY='some path value here'
Importing the values in multiple Makefiles:
# start script and fetch the value
VAR := $(shell ./script.sh | sed -n '/^result: /s/^.*: //p')
all:
#echo VAR=$(VAR)
I would like to see how other people are dealing with the same problem.
Being a better developer is my goal here. :)
Feedback always welcomed.
Environment variables exported in the shell are visible from make, so in a shell script like this:
#!/bin/sh
VAR=value
export VAR
make $*
The Makefile will start with VAR defined to value. That's one way to get variables from a shell script into make.
If you don't want the shell script to run make, you can have a user source it:
$ source script.sh
$ make
The variables set in the script will be visible to make this way too.
Or course there doesn't seem to be any reason you need a shell script here. Stick your configuration into a fragment of a Makefile (which would look almost exactly like your shell script, but not use quotes for multiple word values) and then include Makefile.inc in your main makefile.
Also note that syntax like this:
#!/bin/sh or another commment
VAR=value
export VAR
It equally valid included in a Makefile or sourced into a shell script. So sometimes it's possible to use the same include file in both places!

Prevent a command in a shellscript from being executed inside another shellscript

I am invoking a shellscript inside another shellscript, and the invoked one has a command to delete a folder, which I don't want to be executed, like this
$ rm ../temp -rf
Is there a way to prevent this command from being executed without changing the invoked script contents?
You can define an alias like this in your script:
alias rm='echo SAFE'
By default aliases work only in interactive shells, so you must change this behaviour with:
shopt -s expand_aliases
in your script and source the other script (the one you cannot change):
source the_other_script.sh
or
. the_other_script.sh
This will work unless the other script runs rm in a sub-shell.
Another, safer method is to create your own rm command which does nothing (or just prints out its argument so you know what's going on), put it into a directory and put this directory as the first one in the PATH environment variable like this (Korn shell syntax):
$ export PATH=/path/to/your/dummy/rm/replacement:$PATH

How do I set bash environment variables from a script?

I have some proxy settings that I only occasionally want to turn on, so I don't want to put them in my ~/.bash_profile. I tried putting them directly in ~/bin/set_proxy_env.sh, adding ~/bin to my PATH, and chmod +xing the script but though the script runs, the variables don't stick in my shell. Does anyone know how to get them to stick around for the rest of the shell session?
Use one of:
source <file>
. <file>
In the script use
export varname=value
and also execute the script with:
source set_proxy_env.sh.
The export keyword ensures the variable is marked for automatic inclusion in the environment of subsequently executed commands. Using source to execute a script starts it with the present shell instead of launching a temporary one for the script.
Did you try this:
. ~/bin/set_proxy_env.sh
Running it by itself opens a separate subshell (I think) and sets the variable there. But then the binding is lost after exiting back into your shell. The dot at the front tells it to run it within the same shell.
Also, don't forget to export the variables you need like so: export MYVAR=value

How to handle setting up environment in makefile?

So, to compile my executable, I need to have the library locations set up correctly. The problem is, the setup comes from a bunch of scripts that do the env variable exporting, and what needs to be set up may change (beyond my control) so I need to use those scripts instead of copying their functionality. To compile in regular command line, I need to do something like:
setup library1
setup library2
source some_other_setup_script.bash
g++ blah.c
# setup is a executable on my system that run some scripts
How would I write a makefile that accomplishes that? As far as I tried, the env variable exporting does not carry over (i.e. "export VAR=remember; echo $VAR" won't work)
You can also add environment variables properly with the machinery of GNU make, like so:
export TEST:="Something Good!"
test:
echo $$TEST
This (I think) has different semantics from:
TEST2:="Something not quite so useful?"
test2:
echo ${TEST2}
Which (again, I think) does the substitution within make before passing along to the shell. Note that the export command doesn't work within a target block, just unindented as an immediately executed command.
If variable exporting is not working the way it does on your command line, that suggests that Make is choosing a shell different from the one you're using, with different syntax for handling variables (export VAR=remember; echo $VAR works fine for me). Make uses /bin/sh by default, but you can override this with the SHELL variable, which Make does not import from the environment. I suggest setting SHELL (in the Makefile) to whatever you're using in your environment and trying the export VAR=remember experiment again.
Ultimately you will need to define the variable and execute the compiler in a shell list or even a script, rather than in separate make commands. There are a couple of refinements you could add, however. You could tell make about the script:
maintarget: script.sh blah.c
source script.sh; g++ blah.c
script.sh:
setup include script here
Another thing would be to just execute all that stuff in the same shell
maintarget: blah.c
run this; run that; run the other thing; g++ blah.c
I believe all make versions will run a ; list in the same shell, but you can always force a subshell with (list) or by calling specifically a shell script as a compiler command wrapper.
Don't forget to have the appropriate targets depend on your scripts themselves. BTW, some make versions (pmake aka bsd make) can execute a command when defining a make variable, and all versions of make then exports those. But I don't think gmake can do that.
You could write another shell script that executes all those commands, then prints out variable assignments that make can use. Run the script, pipe its output to a file, then include that file from your Makefile. For example:
Makefile:
all:
echo $(FOO)
test.mk: test.sh
./$< > $#
include test.mk
test.sh
echo "FOO=1"
Running "make" in the directory containing this Makefile produces:
make: Entering directory `/home/luser/build/mktest'
Makefile:7: test.mk: No such file or directory
./test.sh > test.mk
make: Leaving directory `/home/luser/build/mktest'
make: Entering directory `/home/luser/build/mktest'
echo 1
1
make: Leaving directory `/home/luser/build/mktest'
make creates test.mk by running the shell script, then includes it. test.mk contains the output of test.sh, and is parsed as a Makefile. See http://www.gnu.org/software/make/manual/make.html#Include for more details.
We use a variant of this in Mozilla's client.mk to let you define options in a "mozconfig" file:
http://mxr.mozilla.org/mozilla-central/source/client.mk#138
Restatement: How do I get a shell variable into a make file?
Something like:
MYVAR := $(shell echo $(MYVAR)) <any_makefile_additions_here>
So, this defines MYVAR inside a MAKEFILE when an environment variable named MYVAR is also set.
It might be of interest, that, in order to override an option that is already defined in a makefile, make supports (I am referring to GNU Make 3.82, but other version probably too) the option -e.
Example:
Makefile:
CC=gcc
...
Run make:
CC=gcc-4.7
make -e
will use gcc-4.7 instead of gcc.

Resources