GNU Make Under Windows: Check for cygwin in PATH - windows

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.

Related

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)

Putting links to scripts in my cygwin bin

I have made a few python scripts, but is there an easier way to run them? I am using cygwin.
python "C:\Users\Desk\Dropbox\scripts\wsort.py" > data11414_unsorted.txt < data11414_sorted.txt
I want something like this (not typing the path name or "python"):
wsort > data11414_unsorted.txt < data11414_sorted.txt
where wsort is a link to my real wsort.py
Add a
Shebang
to the script
#!/bin/python
then invoke like this
wsort.py > data11414_unsorted.txt < data11414_sorted.txt
First, your question has a Windows-style path (backslashes, beginning with C:) rather than a Cygwin path (/cygdrive/c/Users/Desk/Dropbox/scripts/wsort.py). That implies you're not actually using Cygwin, or if you are, you're ignoring a bunch of warnings.
The below assumes you're using Cygwin Bash (which should be what you get if you start Cygwin Terminal from the Start Menu) and Cygwin Python (which you've installed using Cygwin's setup.exe, not a Windows Python installer). If your not, you're making life more difficult for yourself than you need to.
That out the way, there's a bunch of steps you need to take:
First, make the script executable. Use the chmod command for that, from a Cygwin Bash shell:
chmod +x /cygdrive/c/Users/Desk/Dropbox/scripts/wsort.py
Second, tell the system how to execute it. Add the following line to the top of the script:
#!/bin/python
(That's a "shebang". Python sees it as a comment, so doesn't do anything with it, but Cygwin and other Linux-like systems will use that line to see which program to run the script with. In this case, Python.)
Third, make sure your line endings are correct. Cygwin expects Linux line endings and will fail without them. This may not be a problem, but there's no harm in doing this. Run the following command:
dos2unix /cygdrive/c/Users/Desk/Dropbox/scripts/wsort.py
At this point, you'll be able to call the script by specifying the full path to it in Cygwin. You can't yet run it without specifying where the script is explicitly.
The fourth step is making sure the script is "in your path", ie in one of the folders where Cygwin looks for scripts to run. There are lots of ways to do this, but the most sensible is probably to just add your scripts directory to your path. The following command will add your scripts directory to your path whenever you start a new Cygwin session:
echo 'PATH="/cygdrive/c/Users/Desk/Dropbox/scripts:$PATH"' >>~/.bashrc
You will need to restart your Cygwin terminal for that to take effect, however.
At that point, you'll be able to run the script in Cygwin just by typing wsort.py (and thus use it with redirections and so forth as in your question).
Finally, to be able to call it simply as wsort, there's a number of options. The obvious one is just renaming the file. More usefully (and without copying the file or doing anything liable to break with Dropbox syncing things), try creating an alias:
echo 'alias wsort=wsort.py' >>~/.bashrc
Again, you'll need to restart your Cygwin terminal for that to take effect.
Maybe use an alias ?
alias wsort = "Command_Used"

Why does MinGW/MSys change the binary path?

I'm using Mingw to build a C/C++ project. This project has makefiles beyond my comprehension, and relies on a custom and quite sophisticated toolchain to compile it. It's quite convenient to have GNU tools available on Windows, especially from Windows's cmd shell, but while invoking the tools (make in particular), MinGW seems to change my PATH around.
Cmd does it normally:
echo %PATH% > ... c:\Apps\msys\bin ... (from cmd)
but msys changes this address to :
echo $PATH > ... /usr/bin ...
in msys, even when I print the PATH from a makefile. As a result, make complains that it can't find commands like make, uname, echo, you name it (no pun intended).
Strangely, I managed to get this environment working ages ago without a hitch, but this is the first time I remember seeing this path problem. How can I get MinGW/msys to correctly point to its executables?
richard has a point - there were two different shells fighting over environment variables (not to mention running msys) and so each parsed its own and the system's environment variables differently.
Also make sure that variables defined in your user or system environment are properly written - Windows likes "C:\foo\bar" style paths, but Msys treats them as "/c/foo/bar".

Reading cmd.exe variables inside a MinGW Makefile

I am writing installation in a Makefile in which I need to set the PATH env. variable.
In the windows part of it, I found the following:
set: With set PATH="%PATH%;%CD%" I can change the PATH inside the running environment. There are two problems with this:
The environment is a spawned cmd.exe by make which gets its variable affected and the effect removed as soon as it closes
Even if the previous problem could be solved, still the cmd.exe that calls make would close one day and the modified PATH lost.
setx: A microsoft tool that can permanently change env. variables. According to microsoft itself, this is the only command-line option to do this. Using setx PATH "%PATH%;%CD%" -m however, turns path into the literal %PATH%;%CD% and doesn't replace the variables by their contents!
Note that I am calling make from cmd.exe not cygwin or other modified windows shells that act more like linux. What I'm saying is that, although I can use $(PATH) in my makefile (instead of %PATH%), I can't use pwd (instead of %CD%)
Also note that if in cmd itself I run:
setx PATH "%PATH%;%CD%" -m
it works perfectly. Somehow I need to make make execute this command.
Do you have any idea how to fix this, or what workaround do I have?
P.S. Just for the record, echo "%PATH%;%CD%" in the Makefile also echoes the literal "%PATH%;%CD%" rather than let cmd.exe handle it
Back in the day i Borland C++ Free Command Line tools included a version of make which played well with the dos/windows command line. Probably still floating around somewhere.
Workaround:
Create a .bat file, put the command there, and invoke it from the Makefile.
I still am interested in a direct fix in the Makefile though.

OCaml Installation, not finding binaries

I am attempting to install and run objective-caml on a remote unix server.
I have successfully built and installed all files included in the ocaml package. However, when attempting to use it, eg:
[~]# ocamllex
gives:
-bash: /home1/PATHTOMYHOME/local/bin/ocamllex: /usr/local/bin/ocamlrun: bad interpreter: No such file or directory
Is there any way to tell it to look somewhere else for ocamlrun? The correct directory is in the $PATH variable (ocamlrun works).
You can pass the name of the bytecode file to ocamlrun:
/correct/path/to/ocamlrun /home1/PATHTOMYHOME/local/bin/ocamllex
Alternately, it may just work to edit the first line of the bytecode file: there is a #! and a hardcoded path there. The rest of the file is bytecode though, but if your editor does not mess with it, there is a chance...
As a third solution, use the native-compiled version ocamllex.opt: it does not rely on ocamlrun.
On unix systems, Ocaml bytecode executables begin with a shebang line that gives the path to the bytecode interpreter (ocamlrun). It seems that your executables start with #!/usr/local/bin/ocamlrun. Change this to /home1/PATHTOMYHOME/local/bin/ocamlrun.
If you want ocamlrun to be looked up in the $PATH, change the shebang line to #!/usr/bin/env ocamlrun.
Here's a way to change the path to the bytecode executables in the current directories, leaving other files intact. Remove the *.orig files once you've checked the replacement works.
perl -i.orig -pe 's~^#!.*/ocamlrun.*~#!/usr/bin/env ocamlrun~ if $.==1; close ARGV if eof' *
I suggest that you compile OCaml with ./configure -prefix /home1/PATHTOMYHOME/local. That way all programs will look in the right directories automatically.

Resources