#!/usr/bin/perl -w




use strict;
use Getopt::Long;
use File::Temp;




my %global;
$global{'project_identifier'} = "YASKKSERV";
$global{'version'} = "0.4.0";




# GccIsSupport($gcc_version,
#              3,
#              2,
#              1);
sub GccIsSupport ($$$$)
{
        my $gcc_version = $_[0];
        my $major = $_[1];
        my $minor = $_[2];
        my $sub = $_[3];

        if ($gcc_version >= $major * 1000000 + $minor * 1000 + $sub * 1)
        {
                return !0;
        }
        else
        {
                return 0;
        }
}




sub GccCheck ($$)
{
        my $check_header = $_[0];
        my $check_body = $_[1];

        # thanks! KURASHIKI-san and Debian
        my $temporary_filename_base = '/tmp/yaskkserv.configure.XXXXX';
        my ($wfh_dummy,
            $temporary_filename_o) = File::Temp::mkstemps($temporary_filename_base,
                                                          '.o');
        my ($wfh,
            $temporary_filename_c) = File::Temp::mkstemps($temporary_filename_base,
                                                          '.c');
        print $wfh $check_header;
        print $wfh qq!int main(int argc, char *argv[])\n{\n!;
        print $wfh $check_body;
        print $wfh qq!return 0;\n}\n!;
        close($wfh);

        system("$global{'gplusplus'} -c $temporary_filename_c -o $temporary_filename_o >& /dev/null");
        my $result = $? ? 0 : !0;

        unlink($temporary_filename_o);
        unlink($temporary_filename_c);

        return $result;
}




my %options = (
               'prefix' => '/usr/local'
              );




$global{'data'} .= "# -*- Makefile -*-\n";
$global{'data'} .= "#\n";
$global{'data'} .= "# $0";
foreach (@ARGV)
{
        $global{'data'} .= " $_";
}
$global{'data'} .= "\n";
$global{'data'} .= "#\n";
$global{'data'} .= "# " . localtime() . "\n";
$global{'data'} .= "#\n";
$global{'data'} .= "# * DO NOT EDIT! *\n";
$global{'data'} .= "#\n";




GetOptions("gplusplus=s" => \$options{'gplusplus'},
           "help" => \$options{'help'},
           "enable-syslog" => \$options{'enable-syslog'},
           "disable-syslog" => \$options{'disable-syslog'},
           "enable-error-message" => \$options{'enable-error-message'},
           "disable-error-message" => \$options{'disable-error-message'},
           "precompile" => \$options{'precompile'},
           "prefix=s" => \$options{'prefix'});




if (defined($options{'help'}))
{
        print "$0 usage\n";
        print "    --gplusplus=G++         G++ [default path G++]\n";
        print "    --help                  print this message\n";
        print "    --enable-syslog         enable syslog [default]\n";
        print "    --disable-syslog        disable syslog\n";
        print "    --enable-error-message  enable error message [default]\n";
        print "    --disable-error-message disable error message\n";
        print "    --precompile            use precompile (only G++ 4.0 or newer)\n";
        print "    --prefix=PREFIX         install root directory [/usr/local]\n";
        die;
}




{
        if (defined($options{'gplusplus'}))
        {
                $global{'gplusplus'} = $options{'gplusplus'};
        }
        else
        {
                $global{'gplusplus'} = 'g++';
        }
        $global{'data'} .= "export GPLUSPLUS			= $global{'gplusplus'}\n";
}




{
        my $tmp = 'make';
        $_ = `$tmp -v 2>&1`;
        if (defined($_) and
            /gnu\s*make/im)
        {
                print "GNU Make ($tmp)\n";
        }
        else
        {
                $tmp = 'gmake';
                $_ = `$tmp -v 2>&1`;
                if (defined($_) and
                    /gnu\s*make/im)
                {
                        print "GNU Make ($tmp)\n";
                }
                else
                {
                        $tmp = 'gnumake';
                        $_ = `$tmp -v 2>&1`;
                        if (defined($_) and
                            /gnu\s*make/im)
                        {
                                print "GNU Make ($tmp)\n";
                        }
                        else
                        {
                                print STDERR "*** Warning : GNU Make not found!\n";
                        }
                }
        }
}




{
        $global{'data'} .= "export MKDIR				= mkdir\n";
}




{
        $global{'data'} .= "export RM				= rm\n";
}




{
        $global{'data'} .= "export PERL				= perl\n";
}




{
        $global{'data'} .= "export INSTALL				= install\n";
}




{
        $global{'data'} .= "export PREFIX				= $options{'prefix'}\n";
}




{
        $global{'data'} .= "export PROJECT_IDENTIFIER		= $global{'project_identifier'}\n";
        $_ = $global{'project_identifier'};
        tr/A-Z/a-z/;
        $global{'data'} .= "export PROJECT_IDENTIFIER_LOWER_CASE	= $_\n";
}




{
        $global{'data'} .= "export PROJECT_VERSION			= $global{'version'}\n";
}




{
        $_ = `pwd 2>&1`;
        chomp;
        $global{'project_root'} = $_;
        $global{'data'} .= "export PROJECT_ROOT			= $global{'project_root'}\n";
}




{
        $_ = `uname 2>&1`;
        if (/bsd/i or /darwin/i or
            /cygwin/i or
            /linux/i)
        {
                $global{'architecture'} = 'BSD_CYGWIN_LINUX_GCC';
                $global{'CXXFLAGS_ARCHITECTURE'} = "-D $global{'project_identifier'}_ARCHITECTURE_BSD_CYGWIN_LINUX_GCC";
                $global{'LDFLAGS_ARCHITECTURE'} = '';
        }
        else
        {
                print STDERR "*** Warning : unknown architecture ($_)\n";
                $global{'architecture'} = 'BSD_CYGWIN_LINUX_GCC';
                $global{'CXXFLAGS_ARCHITECTURE'} = "-D $global{'project_identifier'}_ARCHITECTURE_BSD_CYGWIN_LINUX_GCC";
                $global{'LDFLAGS_ARCHITECTURE'} = '';
        }

        if (/cygwin/i)
        {
                $global{'EXECUTE_FILE_SUFFIX'} = '.exe';
        }
        else
        {
                $global{'EXECUTE_FILE_SUFFIX'} = '';
        }

        die "unknown architecture \"$_\"" unless defined($global{'architecture'});

        $global{'data'} .= "export CXXFLAGS_ARCHITECTURE		= $global{'CXXFLAGS_ARCHITECTURE'}\n";
        $global{'data'} .= "export LDFLAGS_ARCHITECTURE		= $global{'LDFLAGS_ARCHITECTURE'}\n";
        $global{'data'} .= "export ARCHITECTURE			= $global{'architecture'}\n";
        $_ = $global{'architecture'};
        tr/A-Z/a-z/;
        $global{'data'} .= "export ARCHITECTURE_LOWER_CASE		= $_\n";
        $global{'data'} .= "export EXECUTE_FILE_SUFFIX  		= $global{'EXECUTE_FILE_SUFFIX'}\n";
}




{
        my @gcc_version;
        foreach (split(/[\r\n]+/,
                       `$global{'gplusplus'} -v 2>&1`))
        {
                if (/^\s*gcc\s+version/ and
                    m!\s+(\d+)\.(\d+)\.?(\d+)?!)
                {
                        @gcc_version = ($1, $2, $3);
                        last;
                }
        }

        if ($#gcc_version == -1)
        {
                $global{'gcc_version'} = 0;
                print STDERR "*** Warning : G++ version failed.\n";
        }
        else
        {
                my $pow = $#gcc_version;
                foreach (@gcc_version)
                {
                        $_ = 0 unless defined($_);
                        $global{'gcc_version'} += $_ * (1000 ** $pow);
                        --$pow;
                }
                my $tmp;
                foreach (@gcc_version)
                {
                        $tmp .= "$_.";
                }
                chop $tmp;
                print "G++ ($tmp)\n";
        }

        unless (GccIsSupport($global{'gcc_version'},
                             3,
                             3,
                             0))
        {
                print STDERR "*** Warning : G++ is too old. You need version 3.3 or newer.\n";
        }
}




if (defined($options{'precompile'}))
{
        if (GccIsSupport($global{'gcc_version'},
                         4,
                         0,
                         0))
        {
                $global{'data'} .= "export USE_PRECOMPILE   		= t\n";
        }
        else
        {
                print STDERR "*** Warning : G++ is too old. You need version 4.0 or newer.\n";
        }
}




{
        $_ = pack("V",
                  1);
        if (unpack("C",
                   $_) == 1)
        {
                $global{'data'} .= "export CXXFLAGS_BYTE_ORDER		= -D $global{'project_identifier'}_ARCHITECTURE_BYTE_ORDER_VAX\n";
        }
        else
        {
                $global{'data'} .= "export CXXFLAGS_BYTE_ORDER		= -D $global{'project_identifier'}_ARCHITECTURE_BYTE_ORDER_NETWORK\n";
        }


        $global{'data'} .= "export CXXFLAGS_CONFIG			= \n";
        unless (defined($options{'disable-syslog'}))
        {
                $global{'data'} .= "CXXFLAGS_CONFIG				+= -D $global{'project_identifier'}_CONFIG_ENABLE_SYSLOG\n";
        }

        unless (defined($options{'disable-error-message'}))
        {
                $global{'data'} .= "CXXFLAGS_CONFIG				+= -D $global{'project_identifier'}_CONFIG_ENABLE_ERROR_MESSAGE\n";
        }
}




{
        my @header = ( 'sys/vfs.h',
                       'mntent.h' );
        foreach (@header)
        {
                my $header_symbol = $_;
                $header_symbol =~ tr/a-z/A-Z/;
                $header_symbol =~ s![\./]!_!g;

                if (GccCheck("#include <$_>\n",
                             ''))
                {
                        $global{'data'} .= "CXXFLAGS_CONFIG				+= -D $global{'project_identifier'}_CONFIG_HEADER_HAVE_$header_symbol\n";
                        print "$_ (found)\n";
                }
                else
                {
                        print "$_ (not found)\n";
                }
        }
}




{
        if (GccCheck("#include <sys/socket.h>\n",
                     "int tmp = MSG_NOSIGNAL;\n"))
        {
                $global{'data'} .= "CXXFLAGS_CONFIG				+= -D $global{'project_identifier'}_CONFIG_MACRO_HAVE_SYMBOL_MSG_NOSIGNAL\n";
                print "MSG_NOSIGNAL (found)\n";
        }
        else
        {
                print "MSG_NOSIGNAL (not found)\n";
        }
}




{
        $_ = `ccache 2>&1`;
        if ($? >= 0)
        {
                $global{'data'} .= "export CCACHE       			= ccache\n";
                print "ccache (found)\n";
        }
        else
        {
                print "ccache (not found)\n";
        }
}




{
        $global{'data'} .= "export CXXFLAGS_OPTIMIZE		= ";

        $_ = `uname -m 2>&1`;
        $global{'data'} .= "-march=k8 " if /x86_64/i;

        if (GccIsSupport($global{'gcc_version'},
                         4,
                         0,
                         0))
        {
                $global{'data'} .= "-O4 ";
        }
        else
        {
# gcc3 Ϥʪ꤬ꥵʲʤХѥХ򤱤뤿
# ץƥޥ٥򲼤ޤ
                $_ = `cat /proc/meminfo 2>&1`;
                my $memory_size = 0 * 1024;
                if (/^MemTotal:\s+(\d+)\s+kB/)
                {
                        $memory_size = $1;
                        print "memory ($memory_size kB)\n";
                }
                else
                {
                        print "memory (unknown)\n";
                }

                if ($memory_size < 320000)
                {
                        $global{'data'} .= "-O1 ";
                        print STDERR "*** Warning : optimize level changed (-O4 to -O1)\n";
                }
                else
                {
                        $global{'data'} .= "-O4 ";
                }
        }
        $global{'data'} .= "-fexpensive-optimizations -ffast-math -fomit-frame-pointer\n";
}




{
        $global{'data'} .= "export CXXFLAGS_OPTIMIZE_SERVER		= ";

        if (GccIsSupport($global{'gcc_version'},
                         3,
                         4,
                         0))
        {
                $global{'data'} .= "--param max-inline-insns-single=131072  --param inline-unit-growth=16384 --param large-function-growth=131072\n";
        }
        else
        {
                $global{'data'} .= "--param max-inline-insns-single=131072\n";
        }
}




{
        $global{'data'} .= "export CXXFLAGS_WARNING			= ";

        if (GccIsSupport($global{'gcc_version'},
                         4,
                         2,
                         0))
        {
                $global{'data'} .= "-Wabi -Wcomments -Wctor-dtor-privacy -Wdeprecated -Wendif-labels -Wfloat-equal -Wformat-extra-args -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winvalid-pch -Wmissing-include-dirs -Wmultichar -Wpragmas -Wredundant-decls -Wundef -Wunused-macros -Wvariadic-macros -Winvalid-offsetof -Wnon-template-friend -Wpmf-conversions -Wstrict-null-sentinel";
                $global{'data'} .= ' ';
        }

        $global{'data'} .= "-Wall -Weffc++ -Wold-style-cast -Woverloaded-virtual -Wsign-promo -Wsynth -W -Wundef -Wshadow -Wlarger-than-16384 -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion -Wsign-compare -Waggregate-return -Wmissing-noreturn -Wredundant-decls -Wnon-virtual-dtor -Wreorder\n";
}




{
        $global{'data'} .= "export CXXFLAGS_WARNING_SERVER		= ";

        $global{'data'} .= "-Winline\n";
}




open(WFH,
     ">Makefile.config") or die;
print WFH $global{'data'};
close(WFH);
