#!/usr/bin/make -f

# To simplify recursion
0 = $(MAKE) -f ../build

# POSIX.1-2008:
#   If the pathname does not begin with a '/' it shall be treated as relative to
#   the current working directory of the process, not relative to the directory
#   containing the makefile.
include ../source.mk
include ../targets.mk

# Hardcode the targets to allow only native compilers for now.
targets = $(OPK_HOST_ARCH)

version = $$(printf '%s\n' '$(OPK_SOURCE_VERSION_UPSTREAM)' | sed 's/+sip.*//')
base_version = $$(printf '%s\n' '$(OPK_SOURCE)' | sed 's/^gcc-//')
target_gnu = $$(oh-architecture $(target))

builddir = obj-$(target)
destdir = dest-$(target)

# /usr/lib/<target>/ld.so is a symbolic link for use by GCC to find the system's
# dynamic linker.  It should be provided by the development package of any
# standard C library.
# ProteanOS GCC should build binaries with an ELF INTERP field as follows:
#   /lib/<target>/<soname>
# <soname> is the SONAME of the target's dynamic linker.
elf_interp = /lib/$(target)/$(elf_interp_soname)
elf_interp_soname = $$(readelf -d "/usr/lib/$(target)/ld.so" | \
	sed -n 's/^.*(SONAME).*\[\([^]]*\)\].*$$/\1/p')

common_opts = \
	--with-pkgversion='GCC for ProteanOS' \
	--program-suffix="-$(base_version)" \
	--enable-linker-build-id \
	--with-system-zlib \
	--disable-multilib \
	--enable-multiarch \
	--without-included-gettext \
	--with-nls \
	--with-sysroot="$${OPK_SYSROOT}" \
	--with-gxx-include-dir="/usr/include/c++-$(base_version)" \
	--enable-clocale=gnu

full_opts = \
	$(common_opts) \
	--enable-shared \
	--enable-threads=posix \
	--enable-languages=c,c++

bootstrap1_opts = \
	$(common_opts) \
	--without-headers \
	--with-newlib \
	--disable-shared \
	--disable-threads \
	--enable-languages=c,c++ \
	--disable-libgomp \
	--disable-libssp

# Defaults:
libdir    = /usr/lib/$(OPK_HOST_ARCH)
libsubdir = /usr/lib/$(OPK_HOST_ARCH)/gcc/$(target_gnu)/$(version)
libsuffix = $$(g++ -print-multi-os-directory)
# Customs:
exec_prefix      = /usr/lib/$(OPK_HOST_ARCH)/$(target)/gcc-$(base_version)
startfile_prefix = /usr/lib/$(target)/gcc-$(base_version)
include_prefix   = /usr/lib/$(target)/gcc-$(base_version)
gcc_gxx_tool_include_dir = /usr/include/$(target)/c++-$(base_version)
dir_macros = \
	"custom_exec_prefix=$(custom_exec_prefix)" \
	"custom_startfile_prefix=$(custom_startfile_prefix)" \
	"custom_include_prefix=$(custom_include_prefix)" \
	"gcc_gxx_tool_include_dir=$(gcc_gxx_tool_include_dir)"

extra_opts =
native_target = bootstrap-lean
cross_target = all-gcc
jobs = 4
include ../local.mk

nop:
	@:

../local.mk:
	>../local.mk

configure-native configure-cross:
	set -e; \
	. "../targets.d/$(target).sh"; \
	if [ 'x$(OPK_HOST_PLAT)' = 'xbootstrap1' ]; then \
		oh-autoconfigure -B "$(builddir)" -t "$(target)" -- \
		$(bootstrap1_opts) \
		$${target_opts} \
		$(extra_opts); \
	else \
		oh-autoconfigure -B "$(builddir)" -t "$(target)" -- \
		$(full_opts) \
		$${target_opts} \
		$(extra_opts); \
	fi

build-gcc-config:
	# Set the default dynamic linker path inserted into ELF INTERP fields.
	# These default values are in header files in gcc/config.  They must be
	# edited here rather than in a patch because any given GCC target
	# configuration can be used by multiple ProteanOS targets.
	# These commands run once per target, but they modify files in the src/
	# directory that other targets might also use, so backups are made.
	set -e; \
	. "../targets.d/$(target).sh"; \
	[ -e "src/gcc/config/$${gcc_config_file}.orig" ] || \
		mv "src/gcc/config/$${gcc_config_file}" \
			"src/gcc/config/$${gcc_config_file}.orig"; \
	define_pattern=".define $${gcc_config_interp_macro}"; \
	sed "s|^\($${define_pattern}\) \".*\"$$|\1 \"$(elf_interp)\"|" \
		"src/gcc/config/$${gcc_config_file}.orig" \
		>"src/gcc/config/$${gcc_config_file}"; \
	[ -e "src/gcc/config/$${gcc_config_fragment}.orig" ] || \
		mv "src/gcc/config/$${gcc_config_fragment}" \
			"src/gcc/config/$${gcc_config_fragment}.orig"; \
	sed "$${gcc_config_fragment_script}" \
		"src/gcc/config/$${gcc_config_fragment}.orig" \
		>"src/gcc/config/$${gcc_config_fragment}"; \
	printf '\nMULTIARCH_DIRNAME = %s\n' "$(target)" \
		>>"src/gcc/config/$${gcc_config_fragment}"

build-native: build-gcc-config
	oh-autobuild -B "$(builddir)" -T $(native_target) -- \
		-j $${JOBS:-$(jobs)} \
		$(dir_macros)
	#if [ '$(OPK_BUILD_ARCH)' = '$(OPK_HOST_ARCH)' ]; then \
	#	cd "$(builddir)" && make -k check; \
	#fi

build-cross: build-gcc-config
	oh-autobuild -B "$(builddir)" -T $(cross_target) -- \
		-j $${JOBS:-$(jobs)} \
		$(dir_macros)

install-native:
	# The -T option is necessary because otherwise:
	#   * oh-autoinstall checks for an "install" target by running make with
	#     the -n option,
	#   * Many commands in GCC makefiles contain the "$(MAKE)" macro
	#     expansion, and
	#   * GNU Make executes any commands that contain "$(MAKE)", even if -n
	#     is specified.
	# See also: <http://gcc.gnu.org/ml/gcc/2013-04/msg00171.html>.
	oh-autoinstall -B "$(builddir)" -d "$(destdir)" -T install -- \
		$(dir_macros)
	# Change the target architecture prefix of files in /usr/bin.
	rm -f $(destdir)/usr/bin/$(target_gnu)-*
	for f in $(destdir)/usr/bin/*; do f="$${f##*/}"; \
		mv $(destdir)/usr/bin/$${f} $(destdir)/usr/bin/$(target)-$${f};\
		ln -s $(target)-$${f} $(destdir)/usr/bin/$${f}; \
	done
	rm -f $(destdir)/usr/bin/$(target)-c++-$(base_version)
	ln -s $(target)-g++-$(base_version) \
		$(destdir)/usr/bin/$(target)-c++-$(base_version)
	# Move files into ProteanOS-style directories.
	mkdir -p $(destdir)$(exec_prefix)
	mv \
		$(destdir)$(libsubdir)/cc1* \
		$(destdir)$(libsubdir)/collect2 \
		$(destdir)$(libsubdir)/lto* \
		$(destdir)$(exec_prefix)
	mkdir -p $(destdir)$(startfile_prefix)
	mv \
		$(destdir)$(libsubdir)/*.o \
		$(destdir)$(libsubdir)/include* \
		$(destdir)$(libsubdir)/*.a \
		$(destdir)$(libsubdir)/*.spec \
		$(destdir)$(libsubdir)/*.so \
		$(destdir)$(startfile_prefix)
	mkdir -p $(destdir)$(gcc_gxx_tool_include_dir)
	mv $(destdir)/usr/include/c++-$(base_version)/$(target_gnu)/* \
		$(destdir)$(gcc_gxx_tool_include_dir)
	mkdir -p $(destdir)$(libdir)
	mv $(destdir)$(libdir)/$(libsuffix)/* $(destdir)$(libdir)
	# Put libgcc_s.so.* under /lib.
	mkdir -p $(destdir)/lib/$(OPK_HOST_ARCH)
	mv $(destdir)$(libdir)/libgcc_s.so.* $(destdir)/lib/$(OPK_HOST_ARCH)
	# Remove libitm files.
	rm -f $(destdir)$(libdir)/libitm.*
	# Remove libquadmath files.
	rm -f $(destdir)$(libdir)/libquadmath.*
	# Remove libtool archives and static libraries.
	rm -f \
		$(destdir)$(libdir)/*.la \
		$(destdir)$(libdir)/*.a \
		$(destdir)$(libsubdir)/*.la \
		$(destdir)$(libsubdir)/plugin/*.la
	# Remove the info directory node.
	rm -f $(destdir)/usr/share/info/dir
	# Remove empty documentation files.
	find $(destdir)/usr/share/man -type f -a -size 0c -a \
		-exec rm -f '{}' ';'
	find $(destdir)/usr/share/info -type f -a -size 0c -a \
		-exec rm -f '{}' ';'
	# TODO: Provide these files in a fixincludes package (arch:any,
	# target-specific?).
	rm -Rf $(destdir)$(libsubdir)/install-tools/
	# TODO: Provide these files in a libstdc++-*-dbg package.
	rm -f $(destdir)$(libdir)/libstdc++.so.*-gdb.py
	rm -Rf $(destdir)/usr/share/gcc-$(version)/python/libstdcxx/
	# TODO: Provide these files in a doc package.
	rm -Rf $(destdir)/usr/share/man/ $(destdir)/usr/share/info/
	# TODO: Provide these files in a gcc-*-plugin-dev package.
	rm -Rf $(destdir)$(libsubdir)/plugin/
	oh-fixperms -d "$(destdir)"
	oh-strip -d "$(destdir)"
	OPK_PACKAGES="\
		$$(printf '%s\n' $${OPK_PACKAGES} | \
			grep -Ev "(gcc|g++)-$(base_version)-.*-.*-.*") \
		gcc-$(base_version)-$(target) \
		g++-$(base_version)-$(target) \
		" oh-installfiles -d "$(destdir)"
	oh-shlibdeps

install-cross:
	oh-autoinstall -B "$(builddir)" -d "$(destdir)" -T install-gcc -- \
		$(dir_macros)
	# Change the target architecture prefix of files in /usr/bin.
	rm -f $(destdir)/usr/bin/$(target_gnu)-*
	for f in $(destdir)/usr/bin/*; do f="$${f##*/}"; \
		mv $(destdir)/usr/bin/$${f} $(destdir)/usr/bin/$(target)-$${f};\
	done
	rm -f $(destdir)/usr/bin/$(target)-c++-$(base_version)
	ln -s $(target)-g++-$(base_version) \
		$(destdir)/usr/bin/$(target)-c++-$(base_version)
	# Move files into ProteanOS-style directories.
	mkdir -p $(destdir)$(exec_prefix)
	mv \
		$(destdir)$(libsubdir)/cc1* \
		$(destdir)$(libsubdir)/collect2 \
		$(destdir)$(libsubdir)/lto* \
		$(destdir)$(exec_prefix)
	rm -Rf \
		$(destdir)$(libsubdir)/*.o \
		$(destdir)$(libsubdir)/include* \
		$(destdir)$(libsubdir)/*.a \
		$(destdir)$(libsubdir)/*.la \
		$(destdir)$(libsubdir)/*.spec \
		$(destdir)$(libsubdir)/*.so \
		$(destdir)$(libsubdir)/install-tools \
		$(destdir)$(libsubdir)/plugin \
		$(destdir)/usr/share/locale \
		$(destdir)/usr/share/man \
		$(destdir)/usr/share/info
	oh-fixperms -d "$(destdir)"
	oh-strip -d "$(destdir)"
	OPK_PACKAGES="\
		gcc-$(base_version)-$(target) \
		g++-$(base_version)-$(target) \
		" oh-installfiles -d "$(destdir)"
	oh-shlibdeps

configure_$(target) build_$(target) install_$(target):
	touch $@

configure_$(target): configure-$(type)
build_$(target): build-$(type)
install_$(target): install-$(type)

configure build install:
	for target in $(targets); do \
		if [ x"$${target}" = x'$(OPK_HOST_ARCH)' ]; then \
			type='native'; \
		else \
			type='cross'; \
		fi; \
		$0 target="$${target}" type="$${type}" "$@_$${target}"; \
	done
	touch $@

configure:
build: configure
install: build