build warns now for non-existing header files
[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 warnings;
35 use Carp;
36 use base 'Module::Build';
37
38 use File::Spec;
39 use Data::Dumper;
40 use Config;
41
42 # Module::Build doesn't seem to have a way to use separate flags for separate
43 # XS files, so here's the override that makes separate files build correctly:
44 sub process_xs
45 {
46         my ($self, $file) = @_;
47         
48         #TODO: call this in MSWin32::process_xs
49         $file =~ s/\\/\//g if( $^O =~ /MSWin.*/ );
50
51         my $properties                   = $self->{properties};
52         my $file_args                    = $self->notes( 'file_flags' )->{$file};
53         my @old_values                   = @$properties{ keys %$file_args };
54         @$properties{ keys %$file_args } = values %$file_args;
55
56         $self->SUPER::process_xs( $file );
57         @$properties{ keys %$file_args } = @old_values;
58 }
59
60
61 # every platform has slightly different library and header paths
62 sub get_arch
63 {
64         my ($self, $os)   = @_;
65         my $modpath       = File::Spec->catfile(
66                 'SDL', 'Build', ucfirst( $os ) . '.pm' );
67         my $module        = 'SDL::Build::' . ucfirst( $os );
68
69         require $modpath or croak "No module for $os platform\n";
70
71         return $module;
72 }
73
74 # which headers are installed?
75 sub find_subsystems
76 {
77         my ($self, $subsystems, $libraries) = @_;
78         my %includes_libs                   = $self->fetch_includes();
79         my %enabled;
80
81         while ( my ($name, $subsystem) = each %$subsystems )
82         {
83                 for my $library (@{ $subsystem->{libraries} })
84                 {
85                         my $lib = $libraries->{$library}
86                                 or croak "Unknown library '$library' for '$name'\n";
87
88                         my ($inc_dir, $link_dir)   =
89                                 $self->find_header( $lib->{header}, \%includes_libs );
90                         $enabled{$name}{ $library } = $inc_dir ? [ $inc_dir, $link_dir ]
91                                 : 0;
92                 }
93         }
94
95         return \%enabled;
96 }
97
98 # set the define flags for the libraries we have
99 sub build_defines
100 {
101         my ($self, $libraries, $build_systems) = @_;
102
103         my %defines;
104
105         while (my ($subsystem, $buildable) = each %$build_systems)
106         {
107                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
108                 {
109                         push @{ $defines{ $subsystem } }, "-D$libraries->{$build}{define}";
110                 }
111         }
112
113         return \%defines;
114 }
115
116 # set the include paths for the libraries we have
117 sub build_includes
118 {
119         my ($self, $libraries, $build_systems) = @_;
120
121         my %includes;
122
123         while (my ($subsystem, $buildable) = each %$build_systems)
124         {
125                 my %sub_include;
126                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
127                 {
128                         $sub_include{ $buildable->{ $build }[0] }++;
129                 }
130
131                 $includes{ $subsystem } = [ map { "-I$_" } keys %sub_include ];
132         }
133
134         return \%includes;
135 }
136
137 # set the linker paths and flags for the libraries we have
138 sub build_links
139 {
140         my ($self, $libraries, $build_systems) = @_;
141
142         my %links;
143
144         while (my ($subsystem, $buildable) = each %$build_systems)
145         {
146                 my %sub_links;
147                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
148                 {
149                         $sub_links{ $buildable->{ $build }[1] }++;
150                         push @{ $links{ $subsystem }{libs} }, "-l$build";
151                 }
152
153                 $links{ $subsystem }{paths} = [ map { "-L$_" } keys %sub_links ];
154         }
155
156         return \%links;
157 }
158
159 # save this all in a format process_xs() can understand
160 sub set_flags
161 {
162         my ($self, $subsystems, $build, $defines, $includes, $links,
163             $sdl_compile, $sdl_link) = @_;
164         my %file_flags;
165         while (my ($subsystem, $buildable) = each %$build)
166         {
167                 my $sub_file     = $subsystems->{$subsystem}{file}{to};
168                 my $sub_includes = join(' ', @{ $includes->{$subsystem} } );
169                 $file_flags{ $sub_file } = 
170                 {
171                         extra_compiler_flags =>
172                         [
173                                 @{ $includes->{$subsystem} },
174                                 (split(' ',$sdl_compile)),
175                                 @{ $defines->{$subsystem} },
176                                 ( defined $Config{usethreads} ? ('-DUSE_THREADS', '-fPIC') : ('-fPIC' )),
177                         ],
178                         extra_linker_flags => 
179                         [
180                                 @{ $links->{$subsystem}{paths} },
181                                 (split(' ',$sdl_link)),
182                                 @{ $links->{$subsystem}{libs} },
183                         ],
184                 },
185         }
186
187         $self->notes( 'file_flags' => \%file_flags );
188 }
189
190 # look for a header somewhere on the system
191 sub find_header
192 {
193         my ($self, $header, $includes) = @_;
194
195         for my $inc_dir (keys %$includes)
196         {
197                 next unless -e File::Spec->catfile( $inc_dir, $header );
198                 return ($inc_dir, $includes->{$inc_dir});
199         }
200
201         print STDERR "Warning: header file '$header' not found.\n";
202         return;
203 }
204
205 sub write_sdl_config
206 {
207         my ($self, $config) = @_;
208         my $path            = File::Spec->catfile(qw( lib SDL Config.pm ));
209         my $dd              = Data::Dumper->new( [ $config ], [ 'sdl_config' ] );
210         my $hash            = $dd->Dump();
211         (my $text           = <<'       END_HEADER' . $hash . <<'       END_FOOTER');
212         package SDL::Config;
213
214         my $sdl_config; 
215         END_HEADER
216
217         sub has
218         {
219                 my ($class, $define) = @_;
220                 scalar grep { $$sdl_config{$_}{$define} } keys %$sdl_config;
221         }
222
223         1;
224         END_FOOTER
225
226         $text =~ s/^\t//gm;
227
228         open my $file, '>', $path or croak "Cannot write to '$path': $!\n";
229         print $file $text;
230 }
231
232
233
234 # Subclass  Darwin to build Objective-C addons
235
236 sub filter_support {
237         my $self = shift;
238         print STDERR "[SDL::Build] generic filter\n";
239         return ();
240 }
241
242 sub process_support_files {
243         my $self = shift;
244         my $p = $self->{properties};
245         return unless $p->{c_source};
246         return unless $p->{c_sources};
247
248         push @{$p->{include_dirs}}, $p->{c_source};
249         unless ( $p->{extra_compiler_flags} && $p->{extra_compiler_flags} =~ /DARCHNAME/) {
250                 $p->{extra_compiler_flags} .=  " -DARCHNAME=" . $self->{config}{archname};
251         }
252         print STDERR "[SDL::Build] extra compiler flags" . $p->{extra_compiler_flags} . "\n";
253
254         foreach my $file (map($p->{c_source} . "/$_", @{$p->{c_sources}})) {
255                 push @{$p->{objects}}, $self->compile_c($file);
256         }
257 }
258
259 # get link flags with a given a sdl_dir
260 sub alt_link_flags
261 {
262         my $self = shift;
263         my $sdl_dir = shift;
264
265         return '-L"'.$sdl_dir.'\lib"';
266 }
267
268 # get compile flags with a given a sdl_dir
269 sub alt_compile_flags
270 {
271          my $self = shift;
272          my $sdl_dir = shift;
273
274          return '-I"'.$sdl_dir.'\include\SDL"'; 
275 }
276
277 # Override to create a MacOS Bundle
278 sub ACTION_bundle
279 {
280         my ($self) = @_;
281         $self->depends_on('build');
282         $self->get_arch($^O)->build_bundle();
283 }
284
285 # Override Install method for darwin
286 sub ACTION_install {
287   my ($self) = @_;
288   require ExtUtils::Install;
289   $self->depends_on('build');
290   ExtUtils::Install::install($self->install_map, 1, 0, $self->{args}{uninst}||0);
291 }
292
293 1;