Choosing a different executable in bash - bash

When I want to run make to generate some executables it always uses the Sun make located
at /usr/local/bin/make rather than GNU make which can be found at /usr/sfw/bin/gmake.
How can I tell the OS to use GNU make rather than Sun's? Do I need to overwrite the path somehow?

For two executables named identically, reorder paths in the PATH variable, since the first match will be used.
Otherwise, define an alias in your ~/.profile or ~/.bashrc file:
alias make="/usr/sfw/bin/gmake"
Or a function:
make() { /usr/sfw/bin/gmake "$#"; }
Note, that aliases work only in interactive mode. Scripts will not see them. Use functions in such case.

you can link /usr/sfw/bin/gmake to /usr/bin for example as long as the directory where you link it to is before /usr/local/bin in the PATH variable
thus
cd /usr/bin
ln -s /usr/sfw/bin/gmake make
just be sure there is no make already in the path.
otherwise you always can call gmake instead of make to use gnu-make and leave make for the sun-version-make.
otherwise you can use the alias as in the previous post

If you're manually running the make command, then simply type gmake instead of make. It will run the GNU version (assuming that your PATH) variable is set properly.
If there's an IDE or some other tool that's invoking make, you need to tell it to use gmake rather than make and the way to do that depends on which tool you're using.

Related

LLDB with Python problem: set PATH exclusively for one executable?

Is there a way of set the PATH variable exclusively for one executable in bash script?
I want to do so because somehow macOS's LLDB requires system-intalled Python, not my Anaconda-managed Python, therefore I need to ensure /usr/bin is at the beginning of PATH. But I prefer Anaconda-managed Python for everyday use, so I don't want to set PATH permanently just to accommodate LLDB.
Temporarily manually writing PATH before and after using LLDB is cumbersome, so I'm thinking about some kind of wrapper script or alias that automates this routine.
P.S. LLDB has the same problem with Homebrew-managed Python.
Environment variables are, by definition, per-process. Each process has a copy of the environment which it can modify for its own reasons.
To override the PATH just for a single invocation, all sh-compatible shells allow you to say
PATH=newvalue executable with arguments
which sets PATH to newvalue for the duration of the execution of executable with arguments, then reverts the value back to its previous state (the current value, or unset if it was unset).
If you want to override something in the environment every time you execute something, you need a wrapper. Assuming you have /usr/local/bin before /usr/bin in your PATH, you could install this in /usr/local/bin/something to override /usr/bin/something with a wrapper:
#!/bin/sh
PATH=newvalue
exec /usr/bin/something "$#"
Remember chmod a+x and of course you need to be root to have write access to this directory in the first place.
For your private needs, a shell function in your .profile or similar is sufficient.
something () {
PATH=newvalue command something "$#"
}

Getting GNU Make to parse shell config files in OSX?

I've got a makefile for installing my personal repo of config files, part of which is compiling my emacs scripts:
compile:
emacs -batch --eval "(progn (load \"~/.emacs\") (byte-recompile-directory \"~/.emacs.d\" 0))"
The problem is, on OSX, I have an alias called "emacs" that points to the Emacs.app binary for use in a terminal, this is defined in my ~/.bash_profile.
Now, no matter what I do, I can't seem to get the shell that Make is calling to read a startup file to load that alias, so that compilation step always fails.
Does anyone know how to do this?
.bash_profile is only read by interactive login shells. Exported environment variables set in it are inherited through the process environment, which means that these settings are generally available to all programs the user starts (if bash is indeed the login shell, of course).
No such inheritance happens for aliases, though. Bash supports exported functions, but that's an obscure feature which can easily break other programs (for example, those which assume that environment variable values do not contain newlines). If you go that route, you may have to use .bashrc instead, to make sure that these functions are exported by interactive bash shells which are not login shells.
I expected the easiest solution is to put a directory like $HOME/bin on the PATH (in .bash_profile or .bashrc, whatever works best) and put an emacs wrapper script into that directory which invokes the actual binary using exec /path/to/Emacs.app "$#" (or maybe just a symbolic link would do).
That is very strange. Aliases are not exported to sub-shells, and the .bash_profile script is only run by interactive shells: make doesn't invoke an interactive shell (by default). So, it's hard to understand how the shell make invokes would see that alias based on the information you've provided.
Maybe you set the BASH_ENV shell variable somewhere? You should never do that, unless you really know what you're doing.
Maybe you reset make's .SHELLFLAGS variable to force a login shell? You shouldn't to that either.
Anyway, you can try using command which avoids aliases etc. Unfortunately make doesn't know this is a shell-built in, so you have to convince it to run a shell. This will be fixed in the next release of GNU make but Apple will never ship that.
compile:
command emacs -batch --eval "(progn (load \"~/.emacs\") (byte-recompile-directory \"~/.emacs.d\" 0))" && true

Using an environment variable in GNU makefile SHELL variable

In a makefile, I have the following:
SHELL = $(SOME_DIRECTORY)/sh
showme:
echo $(SHELL)
This is on MS Windows. The situation is that make is in the PATH (or is being directly invoked) but an acceptable shell (i.e. sh.exe) is NOT in the PATH. Neither is it an option to globally modify the PATH variable to include a sh.exe (too much potential conflict between Cygwin, msysgit, and more). Therefore, make defaults to using the Windows cmd.exe command processor, which is hardly ideal.
It is an option to set a system-wide environment variable other than PATH however. So I had the bright idea of putting a path to the directory containing sh.exe in SOME_DIRECTORY and then using it in the SHELL variable in the makefile. But it's not working for some frustrating reason:
make
echo sh.exe
sh.exe
If I use any other variable than SHELL and echo it, then it prints the expected result. But of course that doesn't have the desired effect of changing the shell.
What am I missing here? What do I need to do to have an environment variable with a custom user-specified name (i.e. not SHELL, PATH, etc.) affect the shell used by make?
Which make are you using? GNU make (gmake) 3.82 is most common and it should work in the way you expect. As MadScientist notes, gmake behaves differently under windows wrt SHELL.
You should be able to set SHELL to the full path of an existing executable file, and gmake will use it to execute commands.
However: if SHELL is not set OR if it is set to a non-existent file, gmake will use the value of ComSpec (mind the caps) as the shell.
Is there an exe at the test path you're using? So $(SOME_DIRECTORY)/sh is an existing exe? (Note that you can omit the '.exe' and gmake will supply it for you, but the file must exist)

GNU Make Under Windows: Check for cygwin in PATH

I have been putting together a makefile in a Windows environment for my team to use. I decided to use MinGW's version of make for Windows. I put that executable with its dependencies into a repository location that should be in everyone's PATH variable. The executable was renamed "make.exe" for simplicity.
Then I realized that I have to account for the case when someone has cygwin's bin folder in their path. Commands like echo, rmdir, and mkdir will call echo.exe, rmdir.exe, and mkdir.exe from cygwin's bin folder. This means that I need to appropriately catch this scenario and use different flags for each command.
I see three cases here:
Cygwin's bin path comes before the path where make.exe is located in the repository. When a team member executes make.exe, they will be executing cygwin's make. Unix-style commands must be used.
Cygwin's bin path comes after the path where make.exe is located in the repository. The correct make.exe will be executed, but I still have to use Unix-style commands.
Cygwin is not installed or not in the PATH. I can use all Windows commands in this case.
I am fine with treating cases 1 and 2 the same. Since MinGW's make and cygwin's make are both based on GNU Make, then I don't see this being much of an issue other than incompatibility issues between versions of GNU Make. Let's just assume that isn't a problem for now.
I have come up with the following check in my makefile.
ifneq (,$(findstring cygdrive,$(PATH))$(findstring cygwin,$(PATH))$(findstring Cygwin,$(PATH)))
#Use Unix style command variables
else
#Use Windows style command variables
endif
Finding "cygdrive" in the path variable means that we are most likely in case 1. Finding "cygwin" or "Cygwin" in the path variable most likely means that we are in case 2. Not finding either string in the path most likely means that we are in case 3.
I am not completely fond of this solution because the cygwin's folder can be renamed or the string "cygwin" or "cygdrive" can be put in the PATH variable without having cygwin installed. One team member is still having issues as he has cygwin's bin path in the PATH variable, but the above does not catch that. I am assuming that he renamed the folder to something else, but I haven't been able to check on that.
So is there a better way to figure out what syntax that I should be using?
Here is another solution that I thought up.
ifeq (a,$(shell echo "a"))
#Use Unix style command variables
else
#Use Windows style command variables
endif
This is based on the fact that 'echo "a"' in Unix will print a (without quotes) but windows will print "a" (with the quotes). If I am using the Unix style echo then I can assume that I am using all Unix commands.
I don't find this solution very elegant though, so I am not marking it as the solution for this question. I think this is better than what I originally had though.
Cygwin make v. MinGW make: Does mingw make support the jobserver, as in can you do make -j5? If not, ${.FEATURES} has jobserver for cygwin make. Maybe load is a good test too.
Cygwin before non-cygwin on path: cygpath.exe is unique to cygwin. You could just look for this in ${PATH}. Unfortunately, Windows users like using spaces in folder names, and there's no way of dealing with this in pure make. $(shell which make) will return /usr/bin/make for cygwin, though a shell invocation on every make run is very smelly.
You don't install a compiler from a repository, is not make a similar case? Just get your users to install cygwin and be done with it.

How to choose a compiler version in Automake?

I have several compilers with the same name but of different versions or location.
The ./configure script seems to stop at the first it finds in PATH. How can I tell Automake to choose one of them according to a custom rule ? I already have a macro which can check the compiler version.
I would like to avoid setting the path by hand (with the FC variable) as it can be cumbersome to type each time the whole path.
In my case, several MPI wrapper compilers are located in different directories with the same name (and added to the PATH by the user).
The idea would be to use something like ./configure --with-intel to find and select the IntelMPI compiler.
My solution is to set up CC and other "precious" variables via a shell script, lots of them for cross compilation. So I have a bunch of shell scripts sitting around with contents like:
export CROSS_COMPILE=arm-linux
export CC=${CROSS_COMPILE}-gcc
...
PATH=$PATH:/some/arm/compiler/bin:/some/arm/compiler/usr/bin # for arm compiler tools
export CFLAGS="..."
to set up the configure configuration. So at configure time I do:
source /path/to/configuration/some-arm-compiler.sh
./configure ...
It saves a lot of typing.
EDIT: So it could work for your particular case something like:
mpi-a.sh
export FC=mpif90
PATH=$PATH:/path/to/mpi-a/bin:/path/to/mpi-a/usr/bin
mpi-b.sh
export FC=mpif90
PATH=$PATH:/path/to/mpi-b/bin:/path/to/mpi-b/usr/bin
So for compiling with one of them:
source /path/to/mpi-a.sh
./configure ...
and the other:
source /path/to/mpi-b.sh
./configure ...
My solution : copy the search strategy of configure in a macro, with a custom matching criterion. Parsing PATH is done by setting the IFS variable (which is already defined in configure). In Bash, finding all the executables would be something like :
#!/bin/bash
IFS=":"
exe="mpif90"
for dir in $PATH
do
if test -f "$dir/$exe"; then
custom_test($dir/$exe)
fi
done
Note: This is recommanded in the manual
If you need to check the behavior of a program as well as find out whether it is present, you have to write your own test for it.

Resources