The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.

use Cwd;
require 'Depends.pm';
#import ExtUtils::Depends;

#print "Configuring Perl/Gtk+... Note that additional packages can be added\n";
#print "by giving switches to Makefile.PL, including:\n\n";

foreach (<*/pkg*.pl>) {
	next unless m!(.*)/pkg(.*)\.pl!;
	my ($name) = lc $1.$2;
	next if $name eq "gtk";
	$package{$name} = $_;
}

foreach (sort keys %package) {
#	print "\t--with-$_\n";
}

#print "\nWe are going to guess some packages, if we guess wrong just use\n";
#print qq{the flags above but change "with" to "without".\n\n};

#print "Unfortunately, these packages aren't terribly smart, and you may need\n";
#print "to tweak the resultant Makefile or the */pkg*.pl files to properly\n";
#print "locate the files needed for a package.\n\n";

# Guess packages
print "You may also use '--lazy-load', which will reduce initial memory usage\n";
print "and loading time, at the cost of some internal glitches.\n\n";

%conf = (
	gdkimlib => "imlib-config",
	gnome => "gnome-config",
);

for(keys %conf) {
	my $v;
	if( ($v = qx($conf{$_} --version)) =~ /[0-9]/ ) {
		# no default submodule compilation
		#print "Guessing $_ - got version $v from $conf{$_}\n";
		#$defaultpack{$_} = 1;
	}
}

@defines = ();

# Starting with Perl 5.005 all embed variables got PL_ prefix
# so, to avoid errorswith sv_undef, we enable polluting name space..
if ($] > 5.004) {
	push @defines, "-DPERL_POLLUTE";
}

sub estr { # Take out blanks
	local $_ = $_[0];
	s/\s+/ /g;
	return $_;
}

# Search for a gnomeConf.sh file (waiting for gnome-config) ...
# One can also 'source' in the shell the proper gnomeConf.sh file
# before running perl Makefile.PL.
if(qx{gnome-config}) {
	print "gnome-config found\n";
	$gnome_version = qx{gnome-config --version};
	$gnome_version =~ s/\S+\s//;
	print "gnome version = $gnome_version\n";
	if($gnome_version =~ /0\.99/ || $gnome_version =~ /^1\./) {
		push @defines, "-DNEW_GNOME";
		print "new gnome found\n";
	}
	$ENV{GNOME_INCLUDEDIR}=estr(qx{gnome-config --cflags gnome});
	$ENV{GNOME_LIBDIR}=estr(qx{gnome-config --libdir});
	$ENV{GNOMEUI_LIBS}=estr(qx{gnome-config --libs gnomeui});
	$ENV{GTKXMHTML_LIBS}=estr(qx{gnome-config --libs gtkxmhtml});
} else {
	print "gnome-config not found!\n";
	print "If you did not enable any gnome options, ";
	print "you can ignore the above message\n";
}

$Lazy = grep($_ eq "--lazy-load", @ARGV);
@ARGV = grep($_ ne "--lazy-load", @ARGV);

$Directory = "";

if ($Lazy) {
	print "\n\nLazy loading enabled -- if anything breaks, please try disabling this.\n";
	push @defines, "-DLAZY_LOAD";
} elsif ($] < 5.004) {
	push @defines, "-DNEED_DERIVED";
}


$libs = `gtk-config --libs`;
$libs = "-L/usr/X11R6/lib -lgtk -lgdk -lglib -lX11 -lXext" if not defined $libs;

$inc = `gtk-config --cflags`;

$libs =~ s/\s+/ /g;
$inc =~ s/\s+/ /g;

$gtk_version = gtk_version();

if ($gtk_version =~ /^(\d+)\.(\d+)\.(\d+)/) {
	$gtk_major = $1;
	$gtk_minor = $2;
	$gtk_micro = $3;
	
	if ($gtk_major < 1 or ($gtk_major == 1 and $gtk_minor == 0 and $gtk_micro == 0)) {
		push @defines, "-DGTK_MAJOR_VERSION=$gtk_major",
						"-DGTK_MINOR_VERSION=$gtk_minor",
						"-DGTK_MICRO_VERSION=$gtk_micro";
	}
	
} else {
	$gtk_major = 0;
	$gtk_minor = 0;
	$gtk_micro = 0;
}

$gtk_hverstr = sprintf("0x%02x%02x%02x", $gtk_major, $gtk_minor, $gtk_micro);
$gtk_hver = hex($gtk_hverstr);

push @defines, "-DGTK_HVER=$gtk_hverstr";

if (not defined $gtk_version) {
	print "Unable to find  Gtk version...\n";
} else {
	print "Located Gtk version $gtk_version...\n";
}

mkdir("build", 0777);

$typemap = [cwd() . "/build/GtkTypemap"];
$object = 'build/GtkDefs.o build/PerlGtkExt.o';
$pm = {
	'build/GtkTypes.pm' => '$(INST_ARCHLIBDIR)/Gtk/Types.pm',
	'build/GtkKeysyms.pm' => '$(INST_ARCHLIBDIR)/Gtk/Keysyms.pm'
};

@clean = qw( build/perl-gtk-ref.pod build/perl-gtk-ds.pod
	build/GtkTypes.pm build/GtkKeysyms.pm build/GtkTypemap build/GtkDefs.c build/GtkDefs.h build/Objects.xpl build/boxed.xsh build/extension.xsh build/objects.xsh 
			build/PerlGtkExt.c build/PerlGtkExt.h build/PerlGtkInt.h build/IFiles.pm */*.o */*/*.o);

%xs = ();
%typemaps = ();
%defs = ();
%boot = ();


{
	local($Directory) = "Gtk/";
	do "Gtk/pkg.pl";
	$inc .= " -I./Gtk";
}

# build the keysyms mapping
{
	my ($incfile) = `gtk-config --prefix`;
	chomp($incfile);
	$incfile .= "/include/gdk/gdkkeysyms.h";

	open(OUT, '>build/GtkKeysyms.pm') || die "Cannot open build/GtkKeysyms.pm: $!";
	print OUT "# DO NOT EDIT!\n";
	print OUT "# This file was built by Gtk's Makefile.PL from $incfile.\n";
	print OUT "\npackage Gtk::Keysyms;\n\n";
	print OUT "%Gtk::Keysyms = (\n";
	if (open(IN, $incfile)) {
		while(<IN>) {
			print OUT "\t'$1'\t=>\t$2,\n" if /^\s*#\s*define\s+GDK_([a-zA-Z0-9_]+)\s+(\w+)$/;
		}
		close(IN);
	}
	print OUT ");\n\n1;\n";
	close(OUT);
}

sub include_package {
	my($p) = @_;
	if (exists $package{$p}) {
		local($Directory);
		my($f) = $package{$p};
		if ($f =~ m!^(.*/)!) {
			$Directory = $1;
			$inc .= " -I./$Directory";
		}
		print "Dir = $Directory\n";
		do $f;
	} else {
		die "Unknown package $p\n";
	}
}

foreach (@ARGV) {
	if (/^--with-/) {
		#include_package($');
		$defaultpack{$'} = 1;
	} elsif(/^--without-/) {
		print "Not including package $'\n";
		delete $defaultpack{$'};
	}
}

for(keys %defaultpack) {
	include_package($_);
}

$inc .= " -I./build";

require "tools/gendefs.pl";

print "Invoking gendefs.pl with [",join(", ",sort {$defs{$a} <=> $defs{$b}} keys %defs), "].\n";
print "Please wait, this may take a moment...\n";

add_headers ('<gtk/gtk.h>', '"GtkTypes.h"', '"GdkTypes.h"', '"MiscTypes.h"');

@a = (	'-f', 'Gtk', 
		'-p', 'Gtk=Gtk',
		'-p', 'GdkGL=Gtk::Gdk::GL',
		'-p', 'GdkRgb=Gtk::Gdk::Rgb',
		'-p', 'Gdk=Gtk::Gdk',
		'-p', 'Gnome=Gnome',
		'-p', 'Panel=Gnome::Panel',
		'-m', 'Gtk');
if ($Lazy) {
	push @a, "-L";
}
foreach (sort {$defs{$a} <=> $defs{$b}} keys %defs) {
	push @a, '-d', $_;
}
foreach (sort {$headers{$a} <=> $headers{$b}} keys %headers) {
	push @a, '-i', $_;
}

#system(@a);
#foreach (split(' ', (do 'Objects.xpl'))) {
#	add_xs($_);
#}

add_raw_xs(gendefs::gendefs(@a));

# documentation
gendefs::gen_doc();
system("./tools/gendoc.pl", keys %xs);

$xfiles = {};

foreach (sort {$xs{$a} <=> $xs{$b}} keys %xs) {
	my($xs) = $_;
	s/\.xs$/.c/;
	#s!^.*/!!;
	$xfiles->{$xs} = $_;

	s/\.c$/.o/;
	$object .= " $_";
	
}

foreach (sort {$c{$a} <=> $c{$b}} keys %c) {
	s/\.c$/.o/;
	$object .= " $_";
}

foreach (<*/.xs>, <*/xs/*.xs>) {
	if (not exists $xfiles->{$_}) {
		s/\.xs$/.c/;
		push @clean, $_;
	}
}

open (EXT, ">build/extension.xsh");
print EXT "\n\n# Do not edit this file, as it is automatically generated by Makefile.PL\n\n";
print EXT "BOOT:\n{\n";

foreach (sort {$boot{$a} <=> $boot{$b}} keys %boot) {
	my($b) = $_;
	$b =~ s/::/__/g;
	$b = "boot_$b";
	print EXT "extern void $b(CV *cv);\n";
}
foreach (sort {$boot{$a} <=> $boot{$b}} keys %boot) {
	my($b) = $_;
	$b =~ s/::/__/g;
	$b = "boot_$b";
	print EXT "callXS($b, cv, mark);\n";
}

print EXT "}\n";
close(EXT);

foreach (sort {$typemap{$a} <=> $typemap{$b}} keys %typemap) {
	push @$typemap, cwd() . "/" . $_;
}

use File::Basename;

foreach ( 'build/GtkDefs.h', 'build/PerlGtkExt.h', 'build/PerlGtkInt.h', 'Gtk/ppport.h', 'Gtk/GtkTypes.h', 'Gtk/GdkTypes.h', 'Gtk/MiscTypes.h', 'tools/gendefs.pl', 'tools/genext.pl', 'tools/gendoc.pl') {
	$pm->{$_} = '$(INST_ARCHLIBDIR)/Gtk/Install/' . basename($_);
}

#$archinstall = join(' ', map( "Gtk/Install/$_", @archinstall));

#open(I, ">build/IFiles.pm");
#print I <<'EOT';
##!/usr/bin/perl
#
#package Gtk::Install::Files;
#
#@typemaps = qw(
#EOT
#
#foreach (@$typemap) {
#	my($b) = basename($_);
#	print I "	$b\n";
#	$pm->{$_} = '$(INST_ARCHLIBDIR)/Gtk/Install/' . $b;
#}
#
#print I <<'EOT';
#);
#
#@defs = qw(
#EOT
#
#foreach (sort {$defs{$a} <=> $defs{$b}} keys %defs) {
#	my($b) = basename($_);
#	print I "	$b\n";
#	#$pm->{$_} = '$(INST_ARCHLIBDIR)/Gtk/Install/' . $b;
#}
#
#print I <<'EOT';
#);
#
#@headers = qw(             
#EOT
#
#foreach (sort {$headers{$a} <=> $headers{$b}} keys %headers) {
#	print I "   $_\n";     
#}
#    
#print I <<'EOT';
#);                         
#    
#EOT
#    
#print I "\$libs = '$libs';\n";
#print I "\$inc = '$inc';\n";
#    
#print I <<'EOT';
#
#$CORE = undef;
#foreach (@INC) {
#	if ( -f $_ . "/Gtk/Install/gendefs.pl") {
#		$CORE = $_ . "/Gtk/Install/";
#		last;
#	}
#}
#
#1;
#
#EOT
#
#close(I);

#$pm->{"IFiles.pm"} = '$(INST_ARCHLIBDIR)/Gtk/Install/Files.pm';

$libs =~ s/(^|\s)-[rR]\S+//g;

@libs = split(/\s+/, $libs);
%seenlibs = ();
@revlibs=();
@lflags=();
foreach (@libs) {
	if (/^-l/) {
		unshift(@revlibs, $_);
	} else {
		unshift(@lflags, $_) unless $seenlibs{$_}++;
	}
}
#print "LIBS=@libs\n";
@libs=();
foreach (@revlibs) {
	unshift(@libs, $_) unless $seenlibs{$_}++;
}

#print "REVLIBS=@revlibs\n";
print "LIBS=@lflags @libs\n";
#exit 0;
$libs = "@lflags @libs";

@L = (LIBS => [$libs]);

if (defined $inc and $inc !~ /^\s*$/) {
	@I = (INC => $inc);
} else {
	@I = (); #e.g, INC => -I/usr/other/include
}

$depend = {'build/GtkDefs.c' => 'build/PerlGtkExt.h build/PerlGtkInt.h'};

ExtUtils::Depends::save_config('Gtk', 'build/IFiles.pm', $inc, $libs, $typemap, [keys %defs], [@defines], [keys %headers], $pm);

WriteMakefile(
	'DISTNAME' => 'Gtk-Perl',
    'NAME'	=> 'Gtk',
    'VERSION_FROM'	=> 'Gtk/Gtk.pm',
    'PM' => $pm,
    'TYPEMAPS' => $typemap,
    'XS' => $xfiles,
    'XSOPT' => '-noversioncheck',
    'DEFINE'	=> join(' ',@defines),
    'DIR'	=> '',
    'OBJECT' => $object,
	'XSPROTOARG' => '-noprototypes',
	'clean' => {FILES => join(' ', @clean) },
	'depend' => $depend,
	'dist' => { COMPRESS=>"gzip", SUFFIX=>"gz" },
	@I,
	@L,
);

sub MY::postamble {

'
Makefile: ' . join(' ',
	sort {$defs{$a} <=> $defs{$b}} keys %defs,
	<*/pkg*.pl>
	) . '

build/PerlGtkExt.h build/PerlGtkExt.c build/PerlGtkInt.h: build/GtkDefs.h tools/genext.pl
	$(PERL) tools/genext.pl Gtk

';



}

sub MY::c_o {
	package MY; # so that "SUPER" works right
	my $inherited = shift->SUPER::c_o(@_);
	$inherited =~ s/CCCMD.*$/$&\n\t\@if test -f `basename \$*.o` -a "`basename \$*.o`" != "\$*.o"; then mv `basename \$*.o` \$*.o; fi/m;
    $inherited;
}

sub MY::const_config
{
	package MY;
	my $self = shift;
	my $flags = $self->{'CCCDLFLAGS'};
	$flags =~ s/(-[fK]?\s*)pic\b/${1}PIC/;
	$self->{'CCCDLFLAGS'} = $flags;
	return $self->SUPER::const_config;
}

sub gtk_version {
	my($result);

	$result = `gtk-config --version`;
	chomp $result;
	
	if (not defined $result) {

		unlink("gtkvertmp.out");

		open(T, ">gtkvertmp.c");
		print T <<'EOT';

#include <stdio.h>
#include <gtk/gtk.h>

int main(int argc, char *argv[])
{
	FILE * f = fopen("gtkvertmp.out", "w");
	fprintf(f,"%d.%d.%d\n", gtk_major_version, gtk_minor_version, gtk_micro_version);
	fclose(f);
	return 0;
}

EOT
		close(T);

		use Config;

		$c = "$Config{cc} $Config{ccflags} $inc gtkvertmp.c $Config{ldflags} $libs $Config{libs} -o gtkvertmp";
		system("$c && ./gtkvertmp");

		unlink("gtkvertmp.c");
		unlink("gtkvertmp.o");
		unlink("gtkvertmp");

		open(T, "<gtkvertmp.out");
		$result = <T>;
		chomp $result;
		close(T);

		unlink("gtkvertmp.out");
	}
	
	return $result;
}


$add = 0;
sub add_xs
{
	foreach (@_) { $xs{$Directory . "xs/" .$_} = $add++; }
}

sub add_raw_xs
{
	foreach (@_) { $xs{$_} = $add++; }
}

sub remove_xs
{
	foreach (@_) { delete $xs{$Directory . "xs/". $_}; }
}

sub add_pm
{
	my($k,$v);
	while (($k,$v) = splice(@_, 0, 2)) {
		$k = $Directory . $k;
		$pm->{$k} = $v;
	}
}

sub add_c
{
	foreach (@_) { $c{$Directory . $_} = $add++; }
}

sub remove_c
{
	foreach (@_) { delete $c{$Directory . $_}; }
}

sub add_typemap
{
	foreach (@_) { $typemap{$Directory . $_} = $add++; }
}

sub remove_typemap
{
	foreach (@_) { delete $typemap{$Directory . $_}; }
}

sub add_defs
{
	foreach (@_) { $defs{$Directory . $_} = $add++; }
}

sub remove_defs
{
	foreach (@_) { delete $defs{$Directory . $_}; }
}

sub add_headers
{
	foreach (@_) { $headers{$_} = $add++; }
}

sub remove_headers
{
	foreach (@_) { delete $headers{$_}; }
}

sub add_boot
{
	foreach (@_) { $boot{$_} = $add++; }
}

sub remove_boot
{
	foreach (@_) { delete $boot{$_}; }
}