1

I'm working in a team of embedded firmware developers. We all use make to build a lot of different targets - binaries, doxygen, release packages etc. Some of the team builds under DOS/mingw32 and others under cygwin. I don't want to / cannot force the whole team to choose only one side. So we try to make our makefiles cross platform compatible and mostly we are successful, but the current solutions have their warts. Specifically we are having a hard time writing cross platform rules for:

  • copy
  • dir exist
  • rmdir
  • rm

We use an os.mk file to choose solutions for current platform like this:

ifeq ($(OS),Windows_NT)
    HASUNAME := $(if $(shell where uname 2> NUL),$(shell echo yes),$(shell echo no))
    ifeq ($(HASUNAME),yes)
        UNAME := $(shell uname)
    else
        UNAME := WIN32
    endif
    ifneq (,$(findstring CYGWIN,$(UNAME)))
        $(shell rm NUL)
        PATHSEP:=/
        COPY:=cp
        RM:=rm -f
        RMDIR:=rm -rf
    else
        ifneq (,$(findstring MINGW,$(UNAME)))
            PATHSEP:=/
            COPY:=cp
            RM:=rm -f
            RMDIR:=rm -rf
        else
            PATHSEP:=\\
            COPY:=copy
            RM:=del /q 2>NUL
            RMDIR:=rmdir /q /s 2>NUL
        endif
    endif
else
    COPY=UNEXPECTED_OS_ERROR
    RM=UNEXPECTED_OS_ERROR
    RMDIR=UNEXPECTED_OS_ERROR
endif

The warts come because of the differences in the different platform implementations of the file functions. E.g. for copy I need to manipulate the arguments because one platform uses slash for path separator and the other uses backslash. Like this:

BOOTSRC:=$(subst /,$(PATHSEP),../boot/build/$(BOARD)/Bootloader.hex)
Bootloader.hex:
        $(COPY) $(BOOTSRC) Bootloader.hex

And DOS has issues with doing rm and rmdir without writing on stderr.

I have implemented dir exist ( [ -d folder ] on cygwin/*nix) as a super short python script, but prefer to not mix python into it if I can avoid it.

import os
import sys

for arg in sys.argv[1:]:
    if not os.path.isdir(arg):
        sys.exit(1)
sys.exit()

It seems CMake was developed partly for this issue: Makefile for DOS/Windows and Cygwin

But I would prefer not to have to switch to CMake.

Can you help me find elegant solutions for the four file operations?

Community
  • 1
  • 1
Holger Bille
  • 2,421
  • 1
  • 16
  • 20

1 Answers1

1

I identify the platform this way.

ifeq '$(findstring ;,$(PATH))' ';'
    UNAME := Windows
else
    UNAME := $(shell uname 2>/dev/null || echo Unknown)
    UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))  # CYGWIN_NT-10.0 -> Cygwin
endif

The UNAME variable is set to Linux, Cygwin, Windows, FreeBSD, NetBSD (or presumably Solaris, Darwin, OpenBSD, AIX, HP-UX), or Unknown. It can then be compared throughout the remainder of the Makefile to separate any OS-sensitive variables and commands.

I discuss this further in another thread.

If you're distinguishing MinGW from other non-Cygwin Windows environments, you may want to replace the first simple assignment with this.

UNAME := $(shell uname 2>NUL || echo Windows)
Ken Jackson
  • 479
  • 4
  • 5