Importing SDLPerl 2.2
[sdlgit/SDL_perl.git] / make / lib / SDL / Build.pm
1 #!/usr/bin/env perl
2 #
3 # Build.pm
4 #
5 # Copyright (C) 2005 David J. Goehrig <dgoehrig@cpan.org>
6 #
7 # ------------------------------------------------------------------------------
8 #
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
13
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
18
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with this library; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 #
23 # ------------------------------------------------------------------------------
24 #
25 # Please feel free to send questions, suggestions or improvements to:
26 #
27 #       David J. Goehrig
28 #       dgoehrig@cpan.org
29 #
30
31 package SDL::Build;
32
33 use strict;
34 use base 'Module::Build';
35
36 use File::Spec;
37 use Data::Dumper;
38 use Config;
39
40 # Module::Build doesn't seem to have a way to use separate flags for separate
41 # XS files, so here's the override that makes separate files build correctly:
42 sub process_xs
43 {
44         my ($self, $file) = @_;
45
46         my $properties                   = $self->{properties};
47         my $file_args                    = $self->notes( 'file_flags' )->{$file};
48         my @old_values                   = @$properties{ keys %$file_args };
49         @$properties{ keys %$file_args } = values %$file_args;
50
51         $self->SUPER::process_xs( $file );
52         @$properties{ keys %$file_args } = @old_values;
53 }
54
55
56 # every platform has slightly different library and header paths
57 sub get_arch
58 {
59         my ($self, $os)   = @_;
60         my $modpath       = File::Spec->catfile(
61                 'SDL', 'Build', ucfirst( $os ) . '.pm' );
62         my $module        = 'SDL::Build::' . ucfirst( $os );
63
64         require $modpath or die "No module for $os platform\n";
65
66         return $module;
67 }
68
69 # which headers are installed?
70 sub find_subsystems
71 {
72         my ($self, $subsystems, $libraries) = @_;
73         my %includes_libs                   = $self->fetch_includes();
74         my %enabled;
75
76         while ( my ($name, $subsystem) = each %$subsystems )
77         {
78                 for my $library (@{ $subsystem->{libraries} })
79                 {
80                         my $lib = $libraries->{$library}
81                                 or die "Unknown library '$library' for '$name'\n";
82
83                         my ($inc_dir, $link_dir)   =
84                                 $self->find_header( $lib->{header}, \%includes_libs );
85                         $enabled{$name}{ $library } = $inc_dir ? [ $inc_dir, $link_dir ]
86                                 : 0;
87                 }
88         }
89
90         return \%enabled;
91 }
92
93 # set the define flags for the libraries we have
94 sub build_defines
95 {
96         my ($self, $libraries, $build_systems) = @_;
97
98         my %defines;
99
100         while (my ($subsystem, $buildable) = each %$build_systems)
101         {
102                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
103                 {
104                         push @{ $defines{ $subsystem } }, "-D$libraries->{$build}{define}";
105                 }
106         }
107
108         return \%defines;
109 }
110
111 # set the include paths for the libraries we have
112 sub build_includes
113 {
114         my ($self, $libraries, $build_systems) = @_;
115
116         my %includes;
117
118         while (my ($subsystem, $buildable) = each %$build_systems)
119         {
120                 my %sub_include;
121                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
122                 {
123                         $sub_include{ $buildable->{ $build }[0] }++;
124                 }
125
126                 $includes{ $subsystem } = [ map { "-I$_" } keys %sub_include ];
127         }
128
129         return \%includes;
130 }
131
132 # set the linker paths and flags for the libraries we have
133 sub build_links
134 {
135         my ($self, $libraries, $build_systems) = @_;
136
137         my %links;
138
139         while (my ($subsystem, $buildable) = each %$build_systems)
140         {
141                 my %sub_links;
142                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
143                 {
144                         $sub_links{ $buildable->{ $build }[1] }++;
145                         push @{ $links{ $subsystem }{libs} }, "-l$build";
146                 }
147
148                 $links{ $subsystem }{paths} = [ map { "-L$_" } keys %sub_links ];
149         }
150
151         return \%links;
152 }
153
154 # save this all in a format process_xs() can understand
155 sub set_flags
156 {
157         my ($self, $subsystems, $build, $defines, $includes, $links,
158             $sdl_compile, $sdl_link) = @_;
159
160         my %file_flags;
161
162         while (my ($subsystem, $buildable) = each %$build)
163         {
164                 my $sub_file     = $subsystems->{$subsystem}{file}{to};
165                 my $sub_includes = join(' ', @{ $includes->{$subsystem} } );
166
167                 $file_flags{ $sub_file } = 
168                 {
169                         extra_compiler_flags =>
170                         [
171                                 @{ $includes->{$subsystem} },
172                                 split(' ',$sdl_compile),
173                                 @{ $defines->{$subsystem} },
174                                 ( defined $Config{usethreads} ? ('-DUSE_THREADS', '-fPIC') : ('-fPIC' )),
175                         ],
176                         extra_linker_flags => 
177                         [
178                                 @{ $links->{$subsystem}{paths} },
179                                 split(' ',$sdl_link),
180                                 @{ $links->{$subsystem}{libs} },
181                         ],
182                 },
183         }
184
185         $self->notes( 'file_flags' => \%file_flags );
186 }
187
188 # look for a header somewhere on the system
189 sub find_header
190 {
191         my ($self, $header, $includes) = @_;
192
193         for my $inc_dir (keys %$includes)
194         {
195                 next unless -e File::Spec->catfile( $inc_dir, $header );
196                 return ($inc_dir, $includes->{$inc_dir});
197         }
198 }
199
200 sub write_sdl_config
201 {
202         my ($self, $config) = @_;
203         my $path            = File::Spec->catfile(qw( lib SDL Config.pm ));
204         my $dd              = Data::Dumper->new( [ $config ], [ 'sdl_config' ] );
205         my $hash            = $dd->Dump();
206         (my $text           = <<'       END_HEADER' . $hash . <<'       END_FOOTER');
207         package SDL::Config;
208
209         my $sdl_config; 
210         END_HEADER
211
212         sub has
213         {
214                 my ($class, $define) = @_;
215                 scalar grep { $$sdl_config{$_}{$define} } keys %$sdl_config;
216         }
217
218         1;
219         END_FOOTER
220
221         $text =~ s/^\t//gm;
222
223         open my $file, '>', $path or die "Cannot write to '$path': $!\n";
224         print $file $text;
225 }
226
227 # Subclass  Darwin to build Objective-C addons
228
229 sub filter_support {
230         my $self = shift;
231         print STDERR "[SDL::Build] generic filter\n";
232         return ();
233 }
234
235 sub process_support_files {
236         my $self = shift;
237         my $p = $self->{properties};
238         return unless $p->{c_source};
239         return unless $p->{c_sources};
240
241         push @{$p->{include_dirs}}, $p->{c_source};
242         unless ( $p->{extra_compiler_flags} && $p->{extra_compiler_flags} =~ /DARCHNAME/) {
243                 $p->{extra_compiler_flags} .=  " -DARCHNAME=" . $self->{config}{archname};
244         }
245         print STDERR "[SDL::Build] extra compiler flags" . $p->{extra_compiler_flags} . "\n";
246
247         foreach my $file (map($p->{c_source} . "/$_", @{$p->{c_sources}})) {
248                 push @{$p->{objects}}, $self->compile_c($file);
249         }
250 }
251
252 # Override to create a MacOS Bundle
253 sub build_bundle
254 {
255         return;
256 }
257
258 # Override Install method for darwin
259 sub ACTION_install {
260   my ($self) = @_;
261   require ExtUtils::Install;
262   $self->depends_on('build');
263   $self->get_arch($^O)->build_bundle();
264   ExtUtils::Install::install($self->install_map, 1, 0, $self->{args}{uninst}||0);
265 }
266
267 1;