60

I would like to have the same Makefile for building on Linux and on Windows. I use the default GNU make on Linux and the mingw32-make (also GNU make) on Windows.

I want the Makefile to detect whether it operates on Windows or Linux.


For example make clean command on Windows looks like:

clean:
    del $(DESTDIR_TARGET)

But on Linux:

clean:
    rm $(DESTDIR_TARGET)

Also I would like to use different directory separator on Windows (\) and Linux (/).


It is possible to detect Windows operating system in Makefile?

PS: I do not want to emulate Linux on Windows (cygwin etc.)

There is similiar question: OS detecting makefile, but I didn't find the answer here.

Sampson
  • 265,109
  • 74
  • 539
  • 565
Tom Pažourek
  • 9,582
  • 8
  • 66
  • 107
  • 5
    Windows is able to handle both slashes "/" and "\" are equivalent. – Ency Oct 30 '10 at 13:17
  • If this is for a substantial project, I wonder if it'd be worth letting autotools handle some of the portability stuff? – Cascabel Oct 30 '10 at 14:30
  • @Jefromi: autotools assumes a basic UNIX toolset (sh, m4, sed, rm, ...). @tomp: Might as well install them on windows (from MSYS or GnuWin) and spend your efforts on the more challenging portability issues. – ephemient Oct 30 '10 at 16:07
  • @ephemient: Ah, right, my bad. I'm not really a windows person. (But now I'm confused - can't the mingw toolchain provide that too? I know, the OP said no linux emulation.) – Cascabel Oct 30 '10 at 16:57
  • 12
    @Ency, the "del" command on Windows doesn't like to be given a "/". – Imbue Jan 20 '11 at 00:28

5 Answers5

63

I solved this by looking for an env variable that will only be set on windows.

ifdef OS
   RM = del /Q
   FixPath = $(subst /,\,$1)
else
   ifeq ($(shell uname), Linux)
      RM = rm -f
      FixPath = $1
   endif
endif

clean:
    $(RM) $(call FixPath,objs/*)

Because %OS% is the type of windows, it should be set on all Windows computers but not on Linux.

The blocks then setups up variables for the different programs as well as a function for converting the forward slashes into backslashes.

You to have to use $(call FixPath,path) when you call an outside command (internal commands work fine). You could also use something like:

/ := /

and then

objs$(/)*

if you like that format better.

Paul Hutchinson
  • 1,578
  • 15
  • 21
49

The SystemRoot trick didn't work for me on Windows XP but this did:

ifeq ($(OS),Windows_NT)
    #Windows stuff
    ...
else
    #Linux stuff
    ....
endif
tomsgd
  • 1,080
  • 1
  • 11
  • 24
  • this might be tricky if you have cygwin installed and make executable comes from cygwin. You will get OS=Windows_NT but you can use Linux commands like mkdir -p. The direction of the directory separator is also important – sagi Mar 30 '20 at 20:54
10

You should probably use the $(RM) variable to remove some files.

Antoine Pelisse
  • 12,871
  • 4
  • 34
  • 34
1

Checking WINDIR or COMSPEC is case-sensitive. Instead, I came up with the following solution, hope that helps someone someday:

# detect if running under unix by finding 'rm' in $PATH :
ifeq ($(wildcard $(addsuffix /rm,$(subst :, ,$(PATH)))),)
WINMODE=1
else
WINMODE=0
endif

ifeq ($(WINMODE),1)
# native windows setup :
UNLINK = del $(subst /,\,$(1))
CAT = type $(subst /,\,$(1))
else
# cross-compile setup :
UNLINK = $(RM) $(1)
CAT = cat $(1)
endif
sezero
  • 61
  • 1
  • 1
0

I would like to have the same Makefile for building on Linux and on Windows.

Maybe you will like CMake