#  Copyright (c) 1997-2021
#  Ewgenij Gawrilow, Michael Joswig, and the polymake team
#  Technische Universität Berlin, Germany
#  https://polymake.org
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------

# build rules for ninja

# compiler flags for build modes: Optimized, Debug, Coverage, and Sanitizer
COptFLAGS = -DPOLYMAKE_DEBUG=0 -DNDEBUG ${CXXOPT}
CDebugFLAGS = -DPOLYMAKE_DEBUG=1 ${CXXDEBUG}
CCovFLAGS = -DPOLYMAKE_DEBUG=1 ${CXXCOV} -DPOLYMAKE_GATHER_CODE_COVERAGE
CSanFLAGS = -DPOLYMAKE_DEBUG=0 -DNDEBUG ${CXXSANITIZE} ${PERLSANITIZE}

# compiler flags for external software provided in bundled extensions
# the only difference now is that it's not instrumented for test coverage
CexternOptFLAGS = ${COptFLAGS}
CexternDebugFLAGS = ${CDebugFLAGS}
CexternCovFLAGS = ${CexternDebugFLAGS}
CexternSanFLAGS = ${CSanFLAGS}

# ccache should not be used for Coverage builds, it distorts the source file paths
COptCACHE = ${CCACHE}
CDebugCACHE = ${CCACHE}
CCovCACHE =
CSanCACHE = ${CCACHE}

# linker flags for build modes
LDOptFLAGS =
LDDebugFLAGS = ${CXXDEBUG}
LDCovFLAGS = ${LDDebugFLAGS} ${CXXCOV}
LDSanFLAGS = ${CXXSANITIZE} ${PERLSANITIZE}

# Make ninja record the compiler version within the command line used for building object files.
# This will enforce recompilation after a compiler upgrade and reconfiguration even if the path to the compiler has not changed.
RecordCompilerVersion = : 'COMPILER_USED=${GCCversion}${CLANGversion}'

# compile a C++ source file
rule cxxcompile
  command = ${CCWRAPPER} ${CmodeCACHE} ${CXX} -c -o $out -MMD -MT $out -MF $out.d ${CsharedFLAGS} ${CXXFLAGS} ${ARCHFLAGS} ${CmodeFLAGS} ${CXXextraFLAGS} ${CXXincludes} $in && ${RecordCompilerVersion}
  description = COMPILE $out
  depfile = $out.d
  deps = gcc

# compile a C source file
rule ccompile
  command = ${CCWRAPPER} ${CmodeCACHE} ${CC} -c -o $out -MMD -MT $out -MF $out.d ${CsharedFLAGS} ${CFLAGS} ${ARCHFLAGS} ${CmodeFLAGS} ${CextraFLAGS} $in && ${RecordCompilerVersion}
  description = COMPILE $out
  depfile = $out.d
  deps = gcc

# prepare a perl extension module source
rule xxs_to_cc
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${ExtUtils_xsubpp} -typemap ${ExtUtils_typemap} ${XSextraTYPEMAPS} --output $out $in
  description = GENERATE $out

# generate a bootstrapping sequence for the callable library
rule gen_xs_bootstrap
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/lib/core/src/perl/createBootstrap.pl $in >$out
  description = GENERATE $out

# generate dummy companions for callable library
rule gen_applib_stubs
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/support/generate_applib_fake.pl $in >$out
  description = GENERATE $out

# fill a static library
rule staticlib
  command = ${CCWRAPPER} ${AR} -rcs $out $in
  description = AR $out

# link a shared module
rule sharedmod
  command = ${CCWRAPPER} ${CXX} ${LDsharedFLAGS} ${ARCHFLAGS} -o $out $in ${LDmodeFLAGS} ${LDextraFLAGS} ${LIBSextra} ${LDFLAGS} ${LIBS}
  description = LINK $out

# link a test executable
rule testexe
  command = ${CCWRAPPER} ${CXX} ${ARCHFLAGS} -o $out $in ${LDmodeFLAGS} ${LDextraFLAGS} ${LIBSextra} ${LDFLAGS} ${LIBS}
  description = LINK $out

# create an empty file as a timestamp of an accomplished task or as a placeholder for something missing
rule emptyfile
  command = touch $out

# create a symbolic link
rule symlink
  command = rm -f $out; ln -s $in $out

# create a symbolic link to a file in the same directory
rule symlink_samedir
  command = ln -sf `basename $in` $out

# generate the list of all targets
rule gen_targets
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/support/generate_ninja_targets.pl $out ${root} $in
  description = GENERATE $out
  generator = 1
  depfile = $out.d
  deps = gcc

# generate the list of all source files
rule gen_file_list
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/support/generate_ninja_targets.pl --$what $out $in
  description = GENERATE $out
  restat = 1

# check the timestamp of a file
rule inspect
  command = : $out
  description = INSPECT $out
  restat = 1

# generate a cpperl module from the input list (JSON)
rule gen_cpperl_mod
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/support/generate_cpperl_modules.pl --gen-rules ${buildroot}/cpperl/gen.ninja ${CPPERLextraFlags} $in $out
  description = GENERATE C++ modules from $in
  restat = 1

# regenerate included target lists if necessary
build ${buildroot}/targets.ninja: gen_targets ${config.file} | ${root}/support/generate_ninja_targets.pl

# generate some source files
rule gen_sources
  command = ${GenerateCommand}
  description = GENERATE $out

# rerun the configuration if the configuration script has changed, unless we are using an alternative perl configuration right now
rule reconfigure
  command = if [ '${build.file}' = build.ninja ]; then ${PERL} ${ADDITIONAL_PERL_INCLUDES} -I${root}/perllib ${root}/support/configure.pl --builddir=${builddir}; else true; fi
  description = RECONFIGURE $out
  restat = 1
  pool = console

# install the core system
rule install_core
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/support/install.pl --root ${root} --builddir ${builddir} --config ${config.file} --mode ${buildmode} ${install_libs}
  description = INSTALL core system in mode ${buildmode} at ${InstallTop}

# install an extension
rule install_ext
  command = ${PERL} ${ADDITIONAL_PERL_INCLUDES} ${root}/support/install.pl --root ${root} --extroot ${extroot} --builddir ${builddir} --config ${root.config.file} --mode ${buildmode}
  description = INSTALL $extroot in mode ${buildmode} at ${InstallTop}/ext
