The problem arises when makefile needs be run on different OS and various setting should be properly set up (escaping, path separator, etc) depending on OS.
The first approach was to use Windows COMSPEC:
ifneq ($(COMSPEC)$(ComSpec),)
## in windows
else
## in linux
endif
This is false positive for Cygwin, because it sees Windows' environment variables and detects Cygwin as Windows.
Then we tried Linux PWD:
ifeq ($(PWD),)
## in windows
else
## in linux, cygwin
endif
However, as a result of integration of off-site tool we have PWD set in windows (one of the perl's modules). So, the detection fails again.
I wonder, what is the best approach to differentiate between Cygwin, Linux, Windows using environment variables?
Cygwin and (tested on Ubuntu) Linux provide an $OSTYPE environment variable, set to cygwin for Cygwin and linux-gnu for (Ubuntu) Linux.
Windows does not have this variable, and so it appears to be the only one you'll need. I suppose it's possible that your Linux doesn't provide it, in which case you can use $OSTYPE to distinguish between Windows and Cygwin and then fall back to uname for Cygwin vs. Linux.
Distinguishing between Windows/not Windows using SHELL is not working for me as proposed by pkh. It's appeared that SHELL variable is defined in makefile running by gmake (mine is ver. 3.81) and it equals to "sh.exe". So, the current working solution for me is extend pkh's idea with distinguishing by .exe Windows executable file extension:
ifneq ($(findstring .exe,$(SHELL)),)
$(warning In Windows)
else
$(warning In Linux/Cygwin)
endif
Assuming you do have gcc available on all your machines (ie you are compiling something using your makefiles), you could use
gcc -dumpmachine
to find out the OS for which gcc builds.
You could use the output to set some variables like WINDOWS, LINUX or store it directly in order to use the information.
On Cygwin the OSTYPE environment variable needs to be exported for make to see it.
Related
I have a Makefile with a target that prepends an environment variable to the shell call (with the usual bash syntax). This is the gist of it:
mytest:
ANSWER=42 echo Hello!
(the real deal is a programme that does something with the ENV ANSWER, but that's irrelevant here)
This works as expected in a linux/bash environment. In windows/cmd.exe environments it works to my surprise in some machines, but fails in others with this error:
> make mytest
MYVAR=42 echo Hello!
'MYVAR' is not recognized as an internal or external command,
operable program or batch file.
make: *** [Makefile:332: mytest] Error 1
Which is what I'd normally expect, since ENVVAR=<value> <command> isn't valid syntax in the windows shell. Apparently Make does some magic that I don't understand.
If I pre-export the ENV this way, it works as expected:
mytest: export ANSWER:=42
mytest:
echo Hello!
But since it works on some windows environments, I'd like to know why and maybe adapt those instead of changing a lot of Makefiles.
All of the environments are using GNU Make version 4.3.
Running on Windows is complicated because GNU make can be built in different ways there. Sometimes it is built to use Windows cmd.exe as its shell. Sometimes it's built to use an installation of sh.exe as its shell (note, GNU make never comes with a shell: the shell is a separate facility provided on the system). And sometimes it's built to use sh.exe if it can find one, else use cmd.exe.
If you're seeing different behaviors on different systems, then the way make was built is different between those systems, and/or different systems have different extra software installed so that some have sh.exe and some don't.
I've come across this question whenever I want a make command to display a file that resulted from following a particular recipe using the operating system's default application for opening that type of file.
For example... I work primarily in Linux. I can generate and view documentation of my code with make docs where I have put the following in my Makefile:
docs:
cd ${DIR_WORKING}/doc/; doxygen Doxyfile
xdg-open ${DIR_WORKING}/doc/html/index.html &
I want to use make docs in Windows and have the same effect. I could alternatively use a user-assigned variable like a $(OPEN) in place of xdg-open. Is there a way to open a file using the default program in Windows and Linux without requiring the user to modify the Makefile? I've never used Autoconf for my codes and hope there is a solution that doesn't depend on going in that direction.
You could consider doing OS detection and in your Makefile initialize the OPEN variable depending on the OS.
ifeq ($(OS),Windows_NT)
OPEN := start
else
UNAME := $(shell uname -s)
ifeq ($(UNAME),Linux)
OPEN := xdg-open
endif
...
In your target:
docs:
cd ${DIR_WORKING}/doc/; doxygen Doxyfile
$(OPEN) ${DIR_WORKING}/doc/html/index.html &
I looked at the following answers for some inspiration with this one.
OS detecting makefile
Open file from the command line on Windows
Here is a Makefile snippet using MAKE_HOST as per user657267.
LINUX:=$(findstring linux,$(MAKE_HOST))
ifeq ($(LINUX),linux)
VDSO_PARSE:=parse_vdso.c
endif
In my case, I was testing time functionality under msys and wsl2 and wanted to minimize library overhead by calling get_time_of_day directly. For the OP, the OS by itself is not enough to guarantee that applications are installed, but this is conceptually as good as the accepted answer and maybe useful to someone.
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.
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".
I have never worked with Linux and hence I am ignorant in the commands.However, I need to use the GNU for win64 environment for one of the programming tools to function. I have downloaded the GNU from cygwin. This package includes gcc and various commands and
shells (sh, bash, etc.) that make the PC have a unix
like environment.
I have to change to the directory of the program code MyPrograms and type "make all".
On opening the terminal of cygwin i get this line >> -bash-4.1$
Question is what is the command for changing to the directory MyPrograms;what do I type in after -bash-4.1$
If your MyPrograms folder is located at C:\MyPrograms, then in Cygwin, type:
cd /cygdrive/c/MyPrograms
Refer to this FAQ