# 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			Platform we're building on
# HOST			Target platform (defaults to build)
# VARIANT		Type of build to perform:
# 				release		-	Release build (default)
# 				debug		-	Debug build
# OPTCFLAGS		Optional C compiler flags for $(VARIANT)
# OPTCXXFLAGS		Optional C++ compiler flags for $(VARIANT)
# OPTLDFLAGS		Optional linker flags for $(VARIANT)
# PREFIX		Absolute installation path prefix 
# 				(defaults to /usr/local)
# LIBDIR		Library installation directory in ${PREFIX}
# 				(defaults to lib)
# INCLUDEDIR	Header installation directory in ${PREFIX}
# 				(defaults to include)
#

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

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

# Default variant to release
ifeq ($(VARIANT),)
  VARIANT := release
endif

###############################################################################
# Determine path used to load us, so we can locate other makefiles etc
###############################################################################

# The directory in which the build system can be found
#
# TODO: This should be NS_BUILDSYSTEM_DIR or similar and is not connected
#       to the BUILD variable.
NSBUILD := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
NSSHARED := $(patsubst %/,%,$(dir $(NSBUILD)))
NSTESTTOOLS := $(NSSHARED)/testtools

###############################################################################
# Bootstrap default tooling
###############################################################################

BUILD_CC ?= cc

###############################################################################
# Host/build platform detection
###############################################################################

# Autodetect host
ifeq ($(HOST),)
  HOST := $(shell $(CC) -dumpmachine)
  ifeq ($(HOST),)
    $(error "Failed to guess HOST")
  endif
else
endif

# Autodetect build if necessary
ifeq ($(BUILD),)
  BUILD := $(shell $(BUILD_CC) -dumpmachine)
  ifeq ($(BUILD),)
    $(error "Failed to guess BUILD")
  endif
endif

ifeq ($(BUILD),$(HOST))
  # Native build

  ifeq ($(HOST),i586-pc-haiku)
    # Building on+for Haiku

    # Default prefix
    BEOS_INSTALL_ENV ?= /boot/common

    # 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

  ifeq ($(findstring openbsd,$(HOST)),openbsd)
    # Building on+for OpenBSD
    CFLAGS := $(CFLAGS) -I$(GCCSDK_INSTALL_ENV)/include -I/usr/local/include
    CXXFLAGS := $(CXXFLAGS) -I$(GCCSDK_INSTALL_ENV)/include -I/usr/local/include
    LDFLAGS := $(LDFLAGS) -L$(GCCSDK_INSTALL_ENV)/lib -L/usr/local/lib

    FLEX ?= gflex
  endif

  ifeq ($(findstring freebsd,$(HOST)),freebsd)
    # Building on+for FreeBSD
    CFLAGS := $(CFLAGS) -I$(GCCSDK_INSTALL_ENV)/include -I/usr/local/include
    CXXFLAGS := $(CXXFLAGS) -I$(GCCSDK_INSTALL_ENV)/include -I/usr/local/include
    LDFLAGS := $(LDFLAGS) -L$(GCCSDK_INSTALL_ENV)/lib -L/usr/local/lib
  endif

  ifeq ($(findstring arwin,$(HOST)),arwin)
    # Building on+for Mac OS X (Darwin) with MAC ports
    CFLAGS := $(CFLAGS) -I/opt/local/include
    CXXFLAGS := $(CXXFLAGS) -I/opt/local/include
    LDFLAGS := $(LDFLAGS) -L/opt/local/lib
  endif

else
  # Cross compiling

  # Make first-stab at identity of CC
  CC__ := $(CC)
  # Improve our guess at the identity of CC
  # (only if CC was not specified by the user)
  ifeq ($(origin CC),default)
    CC__ := $(HOST)-gcc
  endif

  # Search the path for the compiler
  toolpath_ := $(shell /bin/which $(CC__))
  ifeq ($(toolpath_),)
    toolpath_ := /opt/netsurf/$(HOST)/cross/bin/
    CC__  := $(toolpath_)$(HOST)-gcc
    AR__  := $(toolpath_)$(HOST)-ar
    CXX__ := $(toolpath_)$(HOST)-g++
  else
    CC__ := $(realpath $(toolpath_))
    toolpath_ := $(dir $(CC__))
    toolprefix_ := $(subst :,/,$(dir $(subst -,/,$(subst /,:,$(CC__)))))
    ifeq ($(origin AR),default)
      AR__ := $(toolprefix_)-ar
    endif
    ifeq ($(origin CXX),default)
      CXX__ := $(toolprefix_)-g++
    endif
  endif

  # Compute default SDK path
  ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
    GCCSDK_INSTALL_ENV := $(realpath $(toolpath_)../../env)
  endif

  ifeq ($(HOST),arm-unknown-riscos)
    # Cross compiling for RISC OS
    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)
      ifneq ($(findstring arm-unknown-riscos-gcc,$(CC__)),)
        EXEEXT := ,e1f
      else
        EXEEXT := ,ff8
      endif
    else
      EXEEXT := ,ffa
    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

  ifeq ($(HOST),i686-w64-mingw32)
    # Cross compiling for Windows -- assumes mingw toolchain
    GENHTML ?= echo
    LCOV ?= echo
    PKGCONFIG ?= PKG_CONFIG_LIBDIR="$(PREFIX)/lib/pkgconfig:$(GCCSDK_INSTALL_ENV)/lib/pkgconfig:$(GCCSDK_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

    # Default prefix
    PREFIX ?= $(GCCSDK_INSTALL_ENV)
  endif

  # AmigaOS (3/4; m68k/ppc: we can treat them identically)
  ifeq ($(findstring amigaos,$(HOST)),amigaos)
    # Cross compiling for AmigaOS
    PKGCONFIG ?= PKG_CONFIG_LIBDIR="$(PREFIX)/lib/pkgconfig:$(GCCSDK_INSTALL_ENV)/lib/pkgconfig:$(GCCSDK_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

  ifeq ($(HOST),m68k-atari-mint)
    # Cross compiling for FreeMiNT

    ATARIARCH ?= 68020-60

    ifeq ($(ATARIARCH),68000)
       ARCHFLAGS := 
       ARCHDIR :=
    endif
    ifeq ($(ATARIARCH),68020-60)
       ARCHFLAGS := -m$(ATARIARCH)
       ARCHDIR := /$(ATARIARCH)
    endif
    ifeq ($(ATARIARCH),v4e)
       ARCHFLAGS := -mcpu=5475
       ARCHDIR := /m5475
    endif

    CFLAGS := $(CFLAGS) -U__STRICT_ANSI__ -I$(GCCSDK_INSTALL_ENV)/include $(ARCHFLAGS)
    CXXFLAGS := $(CXXFLAGS) -U__STRICT_ANSI__ -I$(GCCSDK_INSTALL_ENV)/include $(ARCHFLAGS)
    LDFLAGS := $(LDFLAGS) -L$(GCCSDK_INSTALL_ENV)/lib$(ARCHDIR)

    PREFIX ?= $(GCCSDK_INSTALL_ENV)
  endif

  ifeq ($(HOST),m5475-atari-mint)
    # Cross compiling for FreeMiNT (m5475)
    CFLAGS := $(CFLAGS) -U__STRICT_ANSI__ -I$(GCCSDK_INSTALL_ENV)/include $(ARCHFLAGS)
    CXXFLAGS := $(CXXFLAGS) -U__STRICT_ANSI__ -I$(GCCSDK_INSTALL_ENV)/include $(ARCHFLAGS)
    LDFLAGS := $(LDFLAGS) -L$(GCCSDK_INSTALL_ENV)/lib/m5475

    PREFIX ?= $(GCCSDK_INSTALL_ENV)
  endif
endif

# Default prefix
PREFIX ?= /usr/local

# Default libdir
LIBDIR ?= lib

# Default includedir
INCLUDEDIR ?= include

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

CP ?= cp

DOXYGEN ?= doxygen

ECHO ?= echo

GENHTML ?= genhtml

BUILD_CXX ?= c++

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

FLEX ?= flex

BISON ?= bison

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

# CCACHE
ifeq ($(origin CCACHE),undefined)
  CCACHE=$(word 1,$(shell ccache -V 2>/dev/null))
endif

# 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 := $(CCACHE) $(CC__)
    else
      CC := $(CCACHE) $(CC)
    endif
  endif
endif

# CXX
ifeq ($(origin CXX),default)
  ifdef CXX__
    CXX := $(CCACHE) $(CXX__)
  else
    CXX := $(CCACHE) $(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 ($(BUILD),arm-unknown-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 2,$(ccvsn)),clang)
    # Some newer clangs have distributor as first word
    # (ie, Debian, Apple, etc)
    toolchain := clang
  endif
  ifeq ($(word 2,$(ccvsn)),LLVM)
    # Apple version is "Apple LLVM" to be differntly awkward
    toolchain := clang
  endif
  ifeq ($(word 1,$(ccvsn)),Open64)
    toolchain := open64
  endif
endif

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

# Detect if the toolchain ought to support sanitizers
SANITIZE_OK=no
ifeq ($(toolchain),gcc)
  GCC_VERSION := $(shell $(CC) -dumpversion -dumpfullversion)
  GCC_MAJOR := $(word 1,$(subst ., ,$(GCC_VERSION)))
  ifeq ($(shell expr $(GCC_MAJOR) \>= 6),1)
    SANITIZE_OK=yes
  endif
else ifeq ($(toolchain),clang)
  SANITIZE_OK=yes
endif

# And fail if we can't sanitize and yet the user asked for it
ifeq ($(MAKECMDGOALS),sanitize)
  ifeq ($(SANITIZE_OK),no)
    $(error Unable to build with sanitizers enabled, compiler not compatible
  endif
endif

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

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

ifeq ($(VARIANT),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)
CXXFLAGS := $(CXXFLAGS) $(OPTCXXFLAGS)
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

################################################################################
# Documentation defaults
################################################################################

DOXYCONF ?= docs/Doxyfile

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

include $(NSBUILD)/Makefile.pkgconfig
