Fixed XS building
[sdlgit/SDL_perl.git] / make / lib / SDL / Build.pm
1 #
2 # Copyright (C) 2004 chromatic
3 # Copyright (C) 2004 David J. Goehrig
4 #
5
6 package SDL::Build;
7
8 use strict;
9 use base 'Module::Build';
10
11 use File::Spec;
12 use Data::Dumper;
13 use Config;
14
15 # Module::Build doesn't seem to have a way to use separate flags for separate
16 # XS files, so here's the override that makes separate files build correctly:
17 sub process_xs
18 {
19         my ($self, $file) = @_;
20
21         my $properties                   = $self->{properties};
22
23         my $file_args                    = $self->notes( 'file_flags' )->{$file};
24         my @old_values                   = @$properties{ keys %$file_args };
25         @$properties{ keys %$file_args } = values %$file_args;
26         $self->SUPER::process_xs( $file );
27         @$properties{ keys %$file_args } = @old_values;
28 }
29
30 # every platform has slightly different library and header paths
31 sub get_arch
32 {
33         my ($self, $os)   = @_;
34         my $modpath       = File::Spec->catfile(
35                 'SDL', 'Build', ucfirst( $os ) . '.pm' );
36         my $module        = 'SDL::Build::' . ucfirst( $os );
37
38         require $modpath or die "No module for $os platform\n";
39
40         return $module;
41 }
42
43 # which headers are installed?
44 sub find_subsystems
45 {
46         my ($self, $subsystems, $libraries) = @_;
47         my %includes_libs                   = $self->fetch_includes();
48         my %enabled;
49
50         while ( my ($name, $subsystem) = each %$subsystems )
51         {
52                 for my $library (@{ $subsystem->{libraries} })
53                 {
54                         my $lib = $libraries->{$library}
55                                 or die "Unknown library '$library' for '$name'\n";
56
57                         my ($inc_dir, $link_dir)   =
58                                 $self->find_header( $lib->{header}, \%includes_libs );
59                         $enabled{$name}{ $library } = $inc_dir ? [ $inc_dir, $link_dir ]
60                                 : 0;
61                 }
62         }
63
64         return \%enabled;
65 }
66
67 # set the define flags for the libraries we have
68 sub build_defines
69 {
70         my ($self, $libraries, $build_systems) = @_;
71
72         my %defines;
73
74         while (my ($subsystem, $buildable) = each %$build_systems)
75         {
76                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
77                 {
78                         push @{ $defines{ $subsystem } }, "-D$libraries->{$build}{define}";
79                 }
80         }
81
82         return \%defines;
83 }
84
85 # set the include paths for the libraries we have
86 sub build_includes
87 {
88         my ($self, $libraries, $build_systems) = @_;
89
90         my %includes;
91
92         while (my ($subsystem, $buildable) = each %$build_systems)
93         {
94                 my %sub_include;
95                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
96                 {
97                         $sub_include{ $buildable->{ $build }[0] }++;
98                 }
99
100                 $includes{ $subsystem } = [ map { "-I$_" } keys %sub_include ];
101         }
102
103         return \%includes;
104 }
105
106 # set the linker paths and flags for the libraries we have
107 sub build_links
108 {
109         my ($self, $libraries, $build_systems) = @_;
110
111         my %links;
112
113         while (my ($subsystem, $buildable) = each %$build_systems)
114         {
115                 my %sub_links;
116                 for my $build (grep { $buildable->{ $_ } } keys %$buildable)
117                 {
118                         $sub_links{ $buildable->{ $build }[1] }++;
119                         push @{ $links{ $subsystem }{libs} }, "-l$build";
120                 }
121
122                 $links{ $subsystem }{paths} = [ map { "-L$_" } keys %sub_links ];
123         }
124
125         return \%links;
126 }
127
128 # save this all in a format process_xs() can understand
129 sub set_flags
130 {
131         my ($self, $subsystems, $build, $defines, $includes, $links,
132             $sdl_compile, $sdl_link) = @_;
133
134         my %file_flags;
135
136         while (my ($subsystem, $buildable) = each %$build)
137         {
138                 my $sub_file     = $subsystems->{$subsystem}{file}{to};
139                 my $sub_includes = join(' ', @{ $includes->{$subsystem} } );
140
141                 $file_flags{ $sub_file } = 
142                 {
143                         extra_compiler_flags =>
144                         [
145                                 @{ $includes->{$subsystem} },
146                                 split(' ',$sdl_compile),
147                                 @{ $defines->{$subsystem} },
148                                 ( defined $Config{usethreads} ? ('-DUSE_THREADS', '-fPIC') : '-fPIC' ),
149                         ],
150                         extra_linker_flags => 
151                         [
152                                 @{ $links->{$subsystem}{paths} },
153                                 split(' ',$sdl_link),
154                                 @{ $links->{$subsystem}{libs} },
155                         ],
156                 },
157         }
158
159         $self->notes( 'file_flags' => \%file_flags );
160 }
161
162 # look for a header somewhere on the system
163 sub find_header
164 {
165         my ($self, $header, $includes) = @_;
166
167         for my $inc_dir (keys %$includes)
168         {
169                 next unless -e File::Spec->catfile( $inc_dir, $header );
170                 return ($inc_dir, $includes->{$inc_dir});
171         }
172 }
173
174 sub write_sdl_config
175 {
176         my ($self, $config) = @_;
177         my $path            = File::Spec->catfile(qw( lib SDL Config.pm ));
178         my $dd              = Data::Dumper->new( [ $config ], [ 'sdl_config' ] );
179         my $hash            = $dd->Dump();
180         (my $text           = <<'       END_HEADER' . $hash . <<'       END_FOOTER');
181         package SDL::Config;
182
183         my $sdl_config; 
184         END_HEADER
185
186         sub has
187         {
188                 my ($class, $define) = @_;
189                 scalar grep { $$sdl_config{$_}{$define} } keys %$sdl_config;
190         }
191
192         1;
193         END_FOOTER
194
195         $text =~ s/^\t//gm;
196
197         open my $file, '>', $path or die "Cannot write to '$path': $!\n";
198         print $file $text;
199 }
200
201 1;