#!/usr/bin/make -f

libgcc_soversion = 1

# 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 will be set in sub-makes.
target = ~none
target_gnu = $$(oh-architecture $(target))

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

include ../targets.d/$(target).mk

# /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}" \
	--enable-clocale=gnu \
	$(target_opts)

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

# Abbreviation for build-gcc-config
tm = src/gcc/config

# Defaults:
libdir    = /usr/lib/$(OPK_HOST_ARCH)
libsubdir = /usr/lib/$(OPK_HOST_ARCH)/gcc/$(target_gnu)/$(version)
libsuffix = $$(g++ -print-multi-os-directory)
def_gcc_gcc_include_dir          = $(libsubdir)/include
def_gcc_fixed_include_dir        = $(libsubdir)/include-fixed
def_gcc_gxx_include_dir          = /usr/include/c++/$(version)
def_gcc_gxx_tool_include_dir     = $(def_gcc_gxx_include_dir)/$(target_gnu)
def_gcc_gxx_backward_include_dir = $(def_gcc_gxx_include_dir)/backward
# Customs:
gccexedir = /usr/lib/$(OPK_HOST_ARCH)/$(target)/gcc/$(base_version)
tgtlibdir = /usr/lib/$(target)/gcc/$(base_version)
gcc_gcc_include_dir          = /usr/include/$(target)/gcc/$(base_version)
gcc_fixed_include_dir        = /usr/include/$(target)/gcc/$(base_version)/fixed
gcc_gxx_include_dir          = /usr/include/c++/$(base_version)
gcc_gxx_tool_include_dir     = /usr/include/$(target)/c++/$(base_version)
gcc_gxx_backward_include_dir = /usr/include/c++/$(base_version)/backward
dir_macros = \
	"gcc_gcc_include_dir=$(gcc_gcc_include_dir)" \
	"gcc_fixed_include_dir=$(gcc_fixed_include_dir)" \
	"gcc_gxx_include_dir=$(gcc_gxx_include_dir)" \
	"gcc_gxx_tool_include_dir=$(gcc_gxx_tool_include_dir)" \
	"gcc_gxx_backward_include_dir=$(gcc_gxx_backward_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; \
	if [ 'x$(OPK_HOST_PLAT)' = 'xbootstrap1' ]; then \
		oh-autoconfigure -B "$(builddir)" -t "$(target)" -- \
			$(bootstrap1_opts) \
			$(extra_opts); \
	else \
		oh-autoconfigure -B "$(builddir)" -t "$(target)" -- \
			$(full_opts) \
			$(extra_opts); \
	fi

# This rule sets (host- and) target-dependent paths in 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.
build-gcc-config:
	[ -e "$(tm)/$(tm_file).orig" ] || \
		mv "$(tm)/$(tm_file)" "$(tm)/$(tm_file).orig"
	# Set the default dynamic linker path inserted into ELF INTERP fields.
	sed "s|^\(#define $(tm_interp_macro)\) \".*\"$$|\1 \"$(elf_interp)\"|" \
		"$(tm)/$(tm_file).orig" >"$(tm)/$(tm_file)"
	# Set macros for executable and startup(/library) file prefixes.
	printf '\n#undef %s\n#define %s "%s"\n' STANDARD_EXEC_PREFIX \
		STANDARD_EXEC_PREFIX "$(tgtlibdir)/" >>"$(tm)/$(tm_file)"
	printf '\n#undef %s\n#define %s "%s"\n' STANDARD_LIBEXEC_PREFIX \
		STANDARD_LIBEXEC_PREFIX "$(gccexedir)/" >>"$(tm)/$(tm_file)"
	[ -e "$(tm)/$(tmake_file).orig" ] || \
		mv "$(tm)/$(tmake_file)" "$(tm)/$(tmake_file).orig"
	sed "$(tmake_script)" "$(tm)/$(tmake_file).orig" >"$(tm)/$(tmake_file)"
	printf '\nMULTIARCH_DIRNAME = %s\n' "$(target)" >>"$(tm)/$(tmake_file)"

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.
	# gcc programs:
	mkdir -p $(destdir)$(gccexedir)
	mv \
		$(destdir)$(libsubdir)/cc1* \
		$(destdir)$(libsubdir)/collect2 \
		$(destdir)$(libsubdir)/lto* \
		$(destdir)$(gccexedir)
	# Start files and gcc libraries:
	mkdir -p $(destdir)$(tgtlibdir)
	mv \
		$(destdir)$(libsubdir)/*.o \
		$(destdir)$(libsubdir)/*.a \
		$(destdir)$(libsubdir)/*.so* \
		$(destdir)$(tgtlibdir)
	# gcc and C++ headers:
	mkdir -p \
		$(destdir)$(gcc_gcc_include_dir) \
		$(destdir)$(gcc_fixed_include_dir) \
		$(destdir)$(gcc_gxx_include_dir) \
		$(destdir)$(gcc_gxx_tool_include_dir) \
		$(destdir)$(gcc_gxx_backward_include_dir)
	mv $(destdir)$(def_gcc_gcc_include_dir)/* \
		$(destdir)$(gcc_gcc_include_dir)
	rmdir $(destdir)$(def_gcc_gcc_include_dir)
	mv $(destdir)$(def_gcc_fixed_include_dir)/* \
		$(destdir)$(gcc_fixed_include_dir)
	rmdir $(destdir)$(def_gcc_fixed_include_dir)
	# def_gcc_gxx_tool_include_dir and def_gcc_gxx_backward_include_dir are
	# subdirectories of def_gcc_gxx_include_dir, so move them first.
	mv $(destdir)$(def_gcc_gxx_tool_include_dir)/* \
		$(destdir)$(gcc_gxx_tool_include_dir)
	rmdir $(destdir)$(def_gcc_gxx_tool_include_dir)
	mv $(destdir)$(def_gcc_gxx_backward_include_dir)/* \
		$(destdir)$(gcc_gxx_backward_include_dir)
	rmdir $(destdir)$(def_gcc_gxx_backward_include_dir)
	mv $(destdir)$(def_gcc_gxx_include_dir)/* \
		$(destdir)$(gcc_gxx_include_dir)
	rmdir $(destdir)$(def_gcc_gxx_include_dir)
	# Target-arch libraries:
	mkdir -p $(destdir)$(libdir)
	mv $(destdir)$(libdir)/$(libsuffix)/* $(destdir)$(libdir)
	# Put *.so links in a versioned directory.   We want links to
	# libfoo.so.x, not libfoo.x.y.z as libtool generates.
	set -e; \
	for link in $(destdir)$(libdir)/*.so; do \
		rm -f $${link}; \
		lib=$$(ls $${link}.* | sed 's|^.*/||; q;'); \
		link=$$(printf '%s\n' $${link} | sed 's|^.*/||;'); \
		ln -sf ../../$${lib} $(destdir)$(tgtlibdir)/$${link}; \
	done
	# Put *.o and *.spec files in a versioned directory.
	mv $(destdir)$(libdir)/*.o $(destdir)$(libdir)/*.spec \
		$(destdir)$(tgtlibdir)
	# Put libgcc_s.so.* under /lib.
	mkdir -p $(destdir)/lib/$(OPK_HOST_ARCH)
	mv $(destdir)$(libdir)/libgcc_s.so.* $(destdir)/lib/$(OPK_HOST_ARCH)
	ln -sf /lib/$(OPK_HOST_ARCH)/libgcc_s.so.$(libgcc_soversion) \
		$(destdir)$(tgtlibdir)/libgcc_s.so
	# Remove libitm files.
	rm -f $(destdir)$(libdir)/libitm.*
	# Remove libmpx files.
	rm -f $(destdir)$(libdir)/libmpx*
	# 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="\
		cpp-$(base_version)-$(target) \
		gcc-$(base_version)-$(target) \
		g++-$(base_version)-$(target) \
		" oh-installfiles -d "$(destdir)"
	OPK_PACKAGES="\
		$$(printf '%s\n' $${OPK_PACKAGES} | \
			grep -Ev "(cpp|gcc|g++)-$(base_version)-.*-.*-.*") \
		" 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)$(gccexedir)
	mv \
		$(destdir)$(libsubdir)/cc1* \
		$(destdir)$(libsubdir)/collect2 \
		$(destdir)$(libsubdir)/lto* \
		$(destdir)$(gccexedir)
	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="\
		cpp-$(base_version)-$(target) \
		gcc-$(base_version)-$(target) \
		g++-$(base_version)-$(target) \
		" oh-installfiles -d "$(destdir)"
	oh-shlibdeps

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

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

configure_ build_ install_:
	set -e; \
	for tgt in $(targets); do \
		if [ x"$${tgt}" = x'$(OPK_HOST_ARCH)' ]; then \
			type='native'; \
		else \
			type='cross'; \
		fi; \
		$(MAKE) -f ../build target=$${tgt} type=$${type} $@$${tgt}; \
	done

build_: configure
install_: build

configure build:
	touch $@

configure: configure_
build: build_
install: install_