# Tools Makefile fragment
#
# Expected inputs:
#
# COMPONENT_TYPE	Type of component:
# 				binary		-	Executable binary
# 				lib-static	-	Static library
# 				lib-shared	-	Shared library
# 				riscos-module	-	RISC OS module
#
# Optional inputs:
#
# BUILD			Type of build to perform:
# 				release		-	Release build (default)
# 				debug		-	Debug build
# OPTCFLAGS		Optional C compiler flags for $(BUILD)
# OPTCXXFLAGS		Optional C++ compiler flags for $(BUILD)
# OPTLDFLAGS		Optional linker flags for $(BUILD)
# TARGET		Target platform (defaults to host)
# PREFIX		Absolute installation path prefix 
# 				(defaults to /usr/local)
#

###############################################################################
# Sanity checks
###############################################################################

ifeq ($(COMPONENT_TYPE),)
  $(error COMPONENT_TYPE not set)
endif

# Default build to release
ifeq ($(BUILD),)
  BUILD := release
endif

###############################################################################
# Host/target platform detection
###############################################################################

# Autodetect host if necessary
ifeq ($(HOST),)
  HOST := $(shell uname -s)
endif

# Simple host sanitisation
ifeq ($(HOST),)
  # Don't ask
  HOST := riscos
else
  ifeq ($(HOST),RISC OS)
    HOST := riscos
  endif

  ifeq ($(HOST),BeOS)
    HOST := beos
  endif
  ifeq ($(HOST),Haiku)
    HOST := haiku
  endif

  ifeq ($(HOST),AmigaOS)
    HOST := amiga
  endif

  ifeq ($(findstring MINGW,$(HOST)),MINGW)
    HOST := windows
  endif
endif

ifeq ($(TARGET),)
  # Default target to host. Please add exceptions as required.
  TARGET := $(HOST)

  ifeq ($(HOST),haiku)
    # This isn't necessarily correct -- they have differences. However, in the 
    # general case, this will work. If there are differences that are actually 
    # important wrt the target platform (as opposed to the build host) then 
    # we'll just have to introduce a haiku target, too.
    TARGET := beos
  endif
endif

# Sanitise HOST and TARGET
# TODO: Ideally, we want the equivalent of s/[^A-Za-z0-9]/_/g here
HOST := $(subst .,_,$(subst -,_,$(subst /,_,$(HOST))))
TARGET := $(subst .,_,$(subst -,_,$(subst /,_,$(TARGET))))

# Now setup our tooling
ifeq ($(TARGET),riscos)
  ifeq ($(HOST),riscos)
    # Building on native RISC OS
    GCCSDK_INSTALL_ENV ?= <NSLibs$$Dir>

    CC__ := gcc
    CXX__ := g++
    CMHG ?= cmunge
    GENHTML ?= echo
    LCOV ?= echo
    PKGCONFIG ?=
    # On certain versions of RISC OS (<>4 || kernel < 8.75),
    # the kernel will clean up the current redirection on
    # OS_Exit, including closing the associated file handles.
    # This is problematic for UnixLib, as it's invariably using
    # those filehandles in a pipe between parent and child processes.
    # This affects us as, anywhere where we shell out and want to
    # capture the output of the child process may fail.
    # Fortunately, if we know the child process is built against
    # UnixLib, then we also know that it won't call OS_Exit when it
    # exits, instead returning directly to our exit handler (and thus
    # preserving the redirection). This only works, however, if the
    # child application is specified using its absolute path, or 
    # found in Run$Path. In the case of Perl, it does not appear in
    # Run$Path, so we must invoke it using its absolute path so that
    # the SharedUnixLibrary successfully detects it as a child process.
    PERL ?= <Perl$$Dir>.bin.perl

    # This is nasty, but needed because $(CURDIR) will 
    # contain colons, and thus confuse make mightily
    $(shell SetMacro Alias$$$(COMPONENT)pwd Set %0 <FileSwitch$$CurrentFilingSystem>:|<FileSwitch$$<FileSwitch$$CurrentFilingSystem>$$CSD>|mUnset Alias$$$(COMPONENT)pwd)
    $(shell $(COMPONENT)pwd $(COMPONENT)$$Dir)
    CURDIR := <$(COMPONENT)$$Dir>
  else
    # Cross compiling for RISC OS
    ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
      ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/env),)
        GCCSDK_INSTALL_ENV := /opt/netsurf/arm-unknown-riscos/env
      else
        GCCSDK_INSTALL_ENV := /home/riscos/env
      endif
    endif

    ifeq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
      ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/cross/bin),)
        GCCSDK_INSTALL_CROSSBIN := /opt/netsurf/arm-unknown-riscos/cross/bin
      else
        GCCSDK_INSTALL_CROSSBIN := /home/riscos/cross/bin
      endif
    endif

    AR__ := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*ar)
    CC__ := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
    CXX__ := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
    CMHG ?= PATH="$(GCCSDK_INSTALL_CROSSBIN):$(PATH)" $(GCCSDK_INSTALL_CROSSBIN)/cmunge
    GENHTML ?= echo
    LCOV ?= echo
    PKGCONFIG ?= PKG_CONFIG_LIBDIR="$(PREFIX)/lib/pkgconfig:$(GCCSDK_INSTALL_ENV)/lib/pkgconfig:$(GCCSDK_INSTALL_ENV)/share/pkgconfig" pkg-config

    ifneq ($(COMPONENT_TYPE),riscos-module)
      ifeq ($(origin CC),default)
        ifneq ($(findstring arm-unknown-riscos-gcc,$(CC__)),)
          EXEEXT := ,e1f
        else
          EXEEXT := ,ff8
        endif
      else
        ifneq ($(findstring arm-unknown-riscos-gcc,$(CC)),)
          EXEEXT := ,e1f
        else
          EXEEXT := ,ff8
        endif
      endif
    else
      EXEEXT := ,ffa
    endif
  endif

  # TODO: this assumes GCC
  CFLAGS := $(CFLAGS) -mpoke-function-name -I$(GCCSDK_INSTALL_ENV)/include
  CXXFLAGS := $(CXXFLAGS) -mpoke-function-name -I$(GCCSDK_INSTALL_ENV)/include
  LDFLAGS := $(LDFLAGS) -L$(GCCSDK_INSTALL_ENV)/lib

  CMHGFLAGS := -p -tgcc -32bit -apcs 3/32/nonreent/fpe2/noswst/nofpr/nofp

  # Default prefix
  PREFIX ?= $(GCCSDK_INSTALL_ENV)
endif

# BeOS-like targets
ifeq ($(TARGET),beos)
  ifeq ($(HOST),beos)
    # Building on BeOS
    CC__ := gcc

    # No pkg-config
    PKGCONFIG ?=

    # Default prefix
    BEOS_INSTALL_ENV ?= /boot/home/config
  else
    ifeq ($(HOST),haiku)
      # Building on Haiku

      # Default prefix
      BEOS_INSTALL_ENV ?= /boot/common
    else
      # TODO: more sensible default
      BEOS_INSTALL_ENV ?= /home/jmb/haiku/env
      BEOS_INSTALL_CROSSBIN ?= /home/jmb/haiku/haiku/generated/cross-tools/bin

      CC__ := $(wildcard $(BEOS_INSTALL_CROSSBIN)/*gcc)
      CXX__ := $(wildcard $(BEOS_INSTALL_CROSSBIN)/*g++)
      AR__ := $(wildcard $(BEOS_INSTALL_CROSSBIN)/*ar)

      PKGCONFIG := PKG_CONFIG_LIBDIR="$(PREFIX)/lib/pkgconfig:$(BEOS_INSTALL_ENV)/lib/pkgconfig:$(BEOS_INSTALL_ENV)/share/pkgconfig" pkg-config
    endif
  endif

  # TODO: this assumes GCC
  CFLAGS := $(CFLAGS) -I$(BEOS_INSTALL_ENV)/include
  CXXFLAGS := $(CXXFLAGS) -I$(BEOS_INSTALL_ENV)/include
  LDFLAGS := $(LDFLAGS) -L$(BEOS_INSTALL_ENV)/lib

  PREFIX ?= $(BEOS_INSTALL_ENV)
endif

# Windows
ifeq ($(TARGET),windows)
  ifeq ($(HOST),windows)
    # Building on Windows
    CC__ := gcc
    CXX__ := g++
    AR__ := ar

    PKGCONFIG ?=
  else
    # Cross compiling for Windows -- assumes mingw toolchain
    MINGW_INSTALL_ENV ?= /usr/local/mingw

    CC__ := i586-mingw32msvc-gcc
    CXX__ := i586-mingw32msvc-g++
    AR__ := i586-mingw32msvc-ar

    PKGCONFIG ?= PKG_CONFIG_LIBDIR="$(PREFIX)/lib/pkgconfig:$(MINGW_INSTALL_ENV)/lib/pkgconfig:$(MINGW_INSTALL_ENV)/share/pkgconfig" pkg-config
  endif

  # TODO: this assumes GCC
  CFLAGS := $(CFLAGS) -U__STRICT_ANSI__ -I$(MINGW_INSTALL_ENV)/include
  CXXFLAGS := $(CXXFLAGS) -U__STRICT_ANSI__ -I$(MINGW_INSTALL_ENV)/include
  LDFLAGS := $(LDFLAGS) -L$(MINGW_INSTALL_ENV)/lib

  # Default prefix
  PREFIX ?= $(MINGW_INSTALL_ENV)
endif

# AmigaOS (3/4; m68k/ppc: we can treat them identically)
ifeq ($(findstring amiga,$(TARGET)),amiga)
  ifeq ($(findstring amiga,$(HOST)),amiga)
    # Building on AmigaOS
    # Nothing to do, as we assume the default tooling works
  else
    # Cross compiling for AmigaOS

    ifeq ($(TARGET),amigaos3)
      GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-unknown-amigaos/env
      GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-unknown-amigaos/cross/bin
    else
      GCCSDK_INSTALL_ENV ?= /opt/netsurf/ppc-amigaos/env
      GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/ppc-amigaos/cross/bin
    endif

    AR__ := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*ar)
    CC__ := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
    CXX__ := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)

    PKGCONFIG ?= PKG_CONFIG_LIBDIR="$(PREFIX)/lib/pkgconfig:$(MINGW_INSTALL_ENV)/lib/pkgconfig:$(MINGW_INSTALL_ENV)/share/pkgconfig" pkg-config

    # TODO: this assumes GCC
    CFLAGS := $(CFLAGS) -U__STRICT_ANSI__ -I$(GCCSDK_INSTALL_ENV)/include
    CXXFLAGS := $(CXXFLAGS) -U__STRICT_ANSI__ -I$(GCCSDK_INSTALL_ENV)/include
    LDFLAGS := $(LDFLAGS) -L$(GCCSDK_INSTALL_ENV)/lib

    PREFIX ?= $(GCCSDK_INSTALL_ENV)
  endif
endif

# Default prefix
PREFIX ?= /usr/local

###############################################################################
# Tool defaults
###############################################################################

CP ?= cp

DOXYGEN ?= doxygen

ECHO ?= echo

GENHTML ?= genhtml

ifeq ($(HOST),$(TARGET))
  HOST_CC ?= $(CC)

  HOST_CXX ?= $(CXX)
else
  HOST_CC ?= cc

  HOST_CXX ?= c++
endif

INSTALL ?= install

LCOV ?= lcov

LN ?= ln

MAKE ?= make

MKDIR ?= mkdir
MKDIRFLAGS ?= -p

MV ?= mv

PERL ?= perl

PKGCONFIG ?= PKG_CONFIG_PATH="$(PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH)" pkg-config

GREP ?= grep

SED ?= sed

TOUCH ?= touch

XSLTPROC ?= xsltproc

###############################################################################
# Override defaulted tools
###############################################################################

# CC
ifeq ($(findstring ccc-analyzer,$(CC)),ccc-analyzer)
    # We're being invoked by scan-build, so export 
    # the compiler we would have used such that
    # scan-build works with cross-compilation.
    # There's no need to do this if we would have
    # used the default compiler.
    ifdef CC__
      export CCC_CC := $(CC__)
    endif
else
  # Only set CC if it's not already set in the 
  # environment and we have a value for it. 
  # Otherwise, leave it to be defaulted.
  ifeq ($(origin CC),default)
    ifdef CC__
      CC := $(CC__)
    endif
  endif
endif

# CXX
ifeq ($(origin CXX),default)
  ifdef CXX__
    CXX := $(CXX__)
  endif
endif

# AR
ifeq ($(origin AR),default)
  ifdef AR__
    AR := $(AR__)
  endif
endif

###############################################################################
# Auto-detect the toolchain
###############################################################################

# Check for GCC first, as that's most likely
# TODO: Using shell redirection like this probably hurts portability
ccspecs := $(shell $(CC) -dumpspecs 2>&1)
ifeq ($(findstring libgcc,$(ccspecs)),libgcc)
  # Looks like GCC
  toolchain := gcc
else
  # Not GCC, so enquire further
  ccvsn := $(shell $(CC) --version 2>&1)
  ifeq ($(ccvsn),)
    # Version string is blank
    ifeq ($(HOST),riscos)
      # For some reason we never see the output of SCL apps, so might be
      # Norcroft.  However it might also be a GCC linked against a buggy
      # UnixLib.
      # TODO: Something more useful than blindly assuming GCC.
      ccvsn := GCC
      # ccvsn := Norcroft
    endif
  endif

  # "Norcroft ..."
  ifeq ($(word 1,$(ccvsn)),Norcroft)
    toolchain := norcroft
  endif
  # "GCC ..."
  ifeq ($(word 1,$(ccvsn)),GCC)
    toolchain := gcc
  endif
  # "clang ..."
  ifeq ($(word 1,$(ccvsn)),clang)
    toolchain := clang
  endif
  ifeq ($(word 1,$(ccvsn)),Apple)
    ifeq ($(word 2,$(ccvsn)),clang)
      # Apple clang
      toolchain := clang
    endif
  endif
endif

ifeq ($(toolchain),)
  $(error Unable to detect toolchain)
endif

# TODO: It would be nice to avoid this hard-coded path
include build/makefiles/Makefile.$(toolchain)

###############################################################################
# Default assembler/compiler/linker/archiver flags
###############################################################################

ifeq ($(BUILD),release)
  OPTCFLAGS ?= $(CCDEF)NDEBUG $(CCOPT)
  OPTCXXFLAGS ?= $(CXXDEF)NDEBUG $(CXXOPT)
else
  OPTCFLAGS ?= $(CCDBG) $(CCNOOPT) $(CCDEF)DEBUG
  OPTCXXFLAGS ?= $(CXXDBG) $(CXXNOOPT) $(CXXDEF)DEBUG
  OPTLDFLAGS ?= $(LDDBG)
endif

ifeq ($(origin ARFLAGS),default)
  ARFLAGS := $(ARFLG)
endif

# TODO: This assumes that the C compiler can cope with assembler
ASFLAGS ?= $(CCAS)

CFLAGS := $(CFLAGS) $(OPTCFLAGS) $(CCDEF)BUILD_TARGET_$(TARGET) $(CCDEF)BUILD_HOST_$(HOST)
CXXFLAGS := $(CXXFLAGS) $(OPTCXXFLAGS) \
		$(CXXDEF)BUILD_TARGET_$(TARGET) $(CXXDEF)BUILD_HOST_$(HOST)

ASFLAGS := $(ASFLAGS) $(CFLAGS)
LDFLAGS := $(LDFLAGS) $(OPTLDFLAGS)

###############################################################################
# lib-shared defaults
###############################################################################

# Default library extension
ifeq ($(COMPONENT_TYPE),lib-static)
  LIBEXT ?= .a
else
  LIBEXT ?= .so
endif

# If we're building a shared library, modify the flags appropriately
ifeq ($(COMPONENT_TYPE),lib-shared)
  # Default CFLAGS/LDFLAGS for shared libraries
  SHAREDCFLAGS ?= $(CCSHR) $(CCDEF)PIC
  SHAREDCXXFLAGS ?= $(CXXSHR) $(CCDEF)PIC
  SHAREDLDFLAGS ?= $(LDSHR)
  SHAREDLDPATH ?= LD_LIBRARY_PATH="$(BUILDDIR):$(LD_LIBRARY_PATH)"
endif

################################################################################
# Package config macros
################################################################################

include build/makefiles/Makefile.pkgconfig
