The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
#!/usr/bin/env perl
#
# Build.pm
#
# Copyright (C) 2005 David J. Goehrig <dgoehrig@cpan.org>
#
# ------------------------------------------------------------------------------
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#
# ------------------------------------------------------------------------------
#
# Please feel free to send questions, suggestions or improvements to:
#
#	David J. Goehrig
#	dgoehrig@cpan.org
#

package My::Builder;

use strict;
use warnings;
use base 'Module::Build';

use Carp;
use File::Spec;
use Config;
use Alien::SDL::ConfigData;

our $config = {};

# Module::Build doesn't seem to have a way to use separate flags for separate
# XS files, so here's the override that makes separate files build correctly:
sub process_xs {
	my ( $self, $file ) = @_;

	my $properties = $self->{properties};
	my $file_args  = $self->notes('file_flags')->{$file};

	return unless defined($file_args);

	my @old_values = @$properties{ keys %$file_args };
	@$properties{ keys %$file_args } = values %$file_args;

	$self->SUPER::process_xs($file);
	@$properties{ keys %$file_args } = @old_values;
}

# which headers are installed?
sub find_subsystems {
	my ( $self, $subsystems, $libraries ) = @_;
	my %found;
	my %enabled;
	while ( my ( $name, $subsystem ) = each %$subsystems ) {
		my $param;
		for my $library ( @{ $subsystem->{libraries} } ) {
			my $lib = $libraries->{$library}
				or Carp::confess "Unknown library '$library' for '$name'\n";
			my $h =
				ref( $lib->{header} ) eq 'ARRAY'
				? $lib->{header}
				: [ $lib->{header} ];
			my $need_check = 0;
			foreach (@$h) {
				$need_check = 1 unless $found{$_};
			}
			if ( !$need_check || Alien::SDL->check_header(@$h) ) {
				$found{$_} = 1 foreach (@$h);
				$param->{libs}->{$library} = 1;
				push @{ $param->{defines} }, "-D$libraries->{$library}{define}";
				push @{ $param->{links} },   "-l$libraries->{$library}{lib}";
			} else {

				# I disabled that, so the libs are compiled but the HAVE_* defines are not set
				# so we can e.g. 'use SDL::Pango;' (FROGGS)
				# $param = undef;

				print "###WARNING### Disabling subsystem '$name'\n";
				last;
			}
		}
		$enabled{$name} = $param if $param;
	}
	return \%enabled;
}

# create mapping table: { SDL::Any::Lib => [ list of libs ], SDL::Any::OtherLib => [ list of libs ] ... }
# to keep information what libs (.dll|.so) to load via Dynaloader for which module
sub translate_table {
	my ( $self, $subsystems, $libraries ) = @_;
	my %ret;
	foreach my $m ( keys %$subsystems ) {
		my $p = $subsystems->{$m}->{file}->{to};
		$p =~ s|^lib/(.*)\.xs|$1|;
		$p =~ s|/|::|g;
		my @list =
			map ( $libraries->{$_}->{lib}, @{ $subsystems->{$m}->{libraries} } );
		$ret{$p} = \@list;
	}
	return \%ret;
}

# save this all in a format process_xs() can understand
sub set_file_flags {
	my $self = shift;
	my %file_flags;
	my %build_systems = %{ $self->notes('build_systems') };

	#TODO:  Search for execinfo.h signal.h and turn this on.
	#	This should also be turned on only during CPAN tests
	my $debug = ' -DNOSIGCATCH '; #default until headers found
	if ( Alien::SDL->check_header(qw(execinfo.h signal.h))
		&& $ENV{AUTOMATED_TESTING} )
	{
		$debug .= ' -g -rdynamic ' unless ( $^O =~ /(win|darwin|bsd)/i );

	} else {
		$debug .= ' -O2 ';
	}

	my $arch = ' ';
	$arch = '-arch' . $ENV{SDL_ARCH} if $ENV{SDL_ARCH};

	while ( my ( $subsystem, $param ) = each %build_systems ) {
		my $sub_file = $self->notes('subsystems')->{$subsystem}{file}{to};
		my $extra_compiler_flags = [
			( split( ' ', $arch . $debug . $self->notes('sdl_cflags') ) ),
			@{ $param->{defines} },
		];
		push(@{$extra_compiler_flags}, '-DUSE_THREADS') if defined $Config{usethreads};
		push(@{$extra_compiler_flags}, '-fPIC')         if $^O ne 'MSWin32';
		$file_flags{$sub_file} = {
			extra_compiler_flags => $extra_compiler_flags,
			extra_linker_flags => [
				( split( ' ', $self->notes('sdl_libs') ) ),
				@{ $param->{links} },
			],
		};
	}
	$self->notes( 'file_flags' => \%file_flags );
}

# override the following functions in My::Builder::<platform> if necessary
sub ACTION_build {
	my $self = shift;

	printf(
		"[Alien::SDL] Build option used:\n\t%s\n",
		${ Alien::SDL::ConfigData->config('build_params') }{'title'} || 'n.a.'
	);
	$self->SUPER::ACTION_build;
	$self->ACTION_bundle;
}

# both special to MacOS/Darwin, somebody should review whether it is still necessary
sub special_build_settings { }
sub build_bundle           { }

# build_bundle() currently defined only for MacOS
sub ACTION_bundle {
	my ($self) = @_;
	$self->depends_on('build');
	$self->build_bundle();
}

# inc/My/Darwin.pm will override Install method for MacOS
sub ACTION_install {
	my ($self) = @_;
	require ExtUtils::Install;
	$self->depends_on('build');
	ExtUtils::Install::install(
		$self->install_map, 1, 0,
		$self->{args}{uninst} || 0
	);
}

sub ACTION_test {
	my ($self) = @_;
	$self->depends_on('build');

	$self->SUPER::ACTION_test();
}

1;