# file      : bootstrap.gmake -*- Makefile -*-
# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license   : MIT; see accompanying LICENSE file

# This makefile requires GNU make 3.81 or later and can be used to bootstrap
# the build system similar to the bootstrap.sh script. Its main advantages over
# the script are support for parallel compilation and an out of tree build.
#
# Similar to the script, the makefile expects to find the libbutl/ or
# libbutl-*/ directory either in the current directory (build2 root) or one
# level up. Both in-tree and out-of-tree builds as well as the 'clean' target
# are supported. The result is saved as build2/b-boot.
#
# Typical in-tree build:
#
# cd build2-X.Y.Z
# make -f bootstrap.gmake -j 8 CXX=g++-7
#
# Typical out-of-tree build:
#
# mkdir build2-boot
# cd build2-boot
# make -f ../build2-X.Y.Z/bootstrap.gmake -j 8 CXX=g++-7
#
# If used on Windows, then this makefile assumes you are building in the
# MinGW environment and sets things up similar to bootstrap-mingw.bat.
#
# The following standard make variables can be used to customize the build:
#
# CXX
# CPPFLAGS
# CXXFLAGS
# LDFLAGS
# LIBS

exe   :=
host  :=
chost :=

ifeq ($(OS),Windows_NT)
  exe   := .exe
  host  := i686-w64-mingw32
  chost := i686-w64-mingw32
  override LIBS += -limagehlp
else
  override LIBS += -lpthread
endif

# Remove all the built-in rules, enable second expansion, etc.
#
.SUFFIXES:
ifeq ($(filter -r,$(MAKEFLAGS)),)
MAKEFLAGS += -r
endif

.DELETE_ON_ERROR:
.SECONDEXPANSION:

# We build in CWD and figure out the source directory based on the makefile
# path.
#
out_root := .
src_root := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

ifeq ($(realpath $(out_root)),$(realpath $(src_root)))
  in_tree := true
else
  in_tree := false
endif

# See if there is libbutl or libbutl-* in src_root or one directory up.
#
libbutl :=
ifeq ($(libbutl),)
  libbutl := $(filter %/,$(wildcard $(src_root)/libbutl/))
  ifeq ($(libbutl),)
    libbutl := $(filter %/,$(wildcard $(src_root)/libbutl-*/))
  endif
endif

ifeq ($(libbutl),)
  libbutl := $(filter %/,$(wildcard $(src_root)/../libbutl/))
  ifeq ($(libbutl),)
    libbutl := $(filter %/,$(wildcard $(src_root)/../libbutl-*/))
  endif
endif

ifeq ($(libbutl),)
  $(error unable to find libbutl, use libbutl=<dir> to specify its location)
endif

ifneq ($(words $(libbutl)),1)
  $(error found multiple libbutl, use libbutl=<dir> to specify its location)
endif

libbutl := $(patsubst %/,%,$(libbutl))

# Figure out libbutl output directory. If we are building in-tree, then build
# libbutl in-tree as well, whether inside or level up. Otherwise -- in the
# libbutl subdirectory.
#
ifeq ($(in_tree),true)
  libbutl_out := $(libbutl)/libbutl
else
  libbutl_out := $(out_root)/libbutl
endif

# Obtain the host triplet.
#
ifeq ($(host),)
  host := $(shell $(src_root)/config.guess)

  ifeq ($(host),)
    $(error unable to guess host triplet, use host=<triplet> to specify)
  endif

  chost := $(host)
else
  ifeq ($(chost),)
    chost := $(shell $(src_root)/config.sub $(host))

    ifeq ($(chost),)
      $(error unable to canonicalize host triplet, use chost=<triplet> to specify)
    endif
  endif
endif

# Figure out the list of source/object files.
#
# Note: list nested subdirectories first (used in clean).
#
sub_dirs := \
config      \
dist        \
bin         \
c           \
cc          \
cxx         \
test/script \
test        \
version     \
install     \
in

build2_src  := $(wildcard $(src_root)/build2/*.cxx)
build2_src  += $(foreach d,$(sub_dirs),$(wildcard $(src_root)/build2/$d/*.cxx))
libbutl_src := $(wildcard $(libbutl)/libbutl/*.cxx)

# Filter out *.test.cxx sources.
#
build2_src  := $(filter-out %.test.cxx,$(build2_src))
libbutl_src := $(filter-out %.test.cxx,$(libbutl_src))

# Note that we use the .b.o object file extension to avoid clashing with the
# build2 builds.
#
build2_obj  := $(patsubst $(src_root)/%.cxx,$(out_root)/%.b.o,$(build2_src))
libbutl_obj := $(patsubst $(libbutl)/libbutl/%.cxx,$(libbutl_out)/%.b.o,$(libbutl_src))

# Build.
#
$(out_root)/build2/b-boot$(exe): $(build2_obj) $(libbutl_obj)
	$(CXX) -std=c++1y $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)

$(out_root)/build2/%.b.o: $(src_root)/build2/%.cxx | $$(dir $$@).
	$(CXX) -I$(libbutl) -I$(src_root) -DBUILD2_BOOTSTRAP -DBUILD2_HOST_TRIPLET=\"$(chost)\" $(CPPFLAGS) -std=c++1y $(CXXFLAGS) -o $@ -c $<

$(libbutl_out)/%.b.o: $(libbutl)/libbutl/%.cxx | $$(dir $$@).
	$(CXX) -I$(libbutl) -DBUILD2_BOOTSTRAP $(CPPFLAGS) -std=c++1y $(CXXFLAGS) -o $@ -c $<

.PRECIOUS: %/.
%/. :
	mkdir -p $*

.PHONY: all
all: $(out_root)/build2/b-boot$(exe)

# Clean.
#
.PHONY: clean cleano

cleano:
	rm -f $(build2_obj)
	rm -f $(libbutl_obj)

clean: cleano
	rm -f $(out_root)/build2/b-boot$(exe)
ifeq ($(in_tree),false)
	rm -fd $(foreach d,$(sub_dirs),$(out_root)/build2/$d) $(out_root)/build2 $(libbutl_out)
endif