File Coverage

blib/lib/SPVM/Builder.pm
Criterion Covered Total %
statement 96 144 66.6
branch 11 26 42.3
condition 3 9 33.3
subroutine 18 23 78.2
pod 0 10 0.0
total 128 212 60.3


line stmt bran cond sub pod time code
1             package SPVM::Builder;
2              
3 278     278   96996 use strict;
  278         558  
  278         7815  
4 278     278   1294 use warnings;
  278         496  
  278         6999  
5              
6 278     278   1339 use Carp 'confess';
  278         529  
  278         12521  
7 278     278   1534 use Scalar::Util 'weaken';
  278         597  
  278         13309  
8 278     278   1738 use File::Path 'mkpath';
  278         533  
  278         19308  
9 278     278   2050 use File::Basename 'dirname', 'basename';
  278         681  
  278         14370  
10              
11 278     278   7409 use SPVM ();
  278         668  
  278         8967  
12              
13 278     278   137054 use SPVM::Builder::CC;
  278         1046  
  278         10923  
14 278     278   115347 use SPVM::Builder::Compiler;
  278         796  
  278         8418  
15 278     278   117304 use SPVM::Builder::Runtime;
  278         794  
  278         8394  
16 278     278   109785 use SPVM::Builder::Env;
  278         1008  
  278         9047  
17 278     278   106896 use SPVM::Builder::Stack;
  278         1043  
  278         346221  
18              
19             # Fields
20             sub build_dir {
21 863     863 0 1895 my $self = shift;
22 863 50       2600 if (@_) {
23 0         0 $self->{build_dir} = $_[0];
24 0         0 return $self;
25             }
26             else {
27 863         3095 return $self->{build_dir};
28             }
29             }
30              
31             sub include_dirs {
32 2023     2023 0 7635 my $self = shift;
33 2023 50       5015 if (@_) {
34 0         0 $self->{include_dirs} = $_[0];
35 0         0 return $self;
36             }
37             else {
38 2023         11003 return $self->{include_dirs};
39             }
40             }
41              
42             sub new {
43 2102     2102 0 3349111 my $class = shift;
44            
45             my $self = {
46 2102         7218 include_dirs => [map { "$_/SPVM" } @INC],
  24621         58177  
47             @_
48             };
49            
50 2102   33     12671 bless $self, ref $class || $class;
51            
52 2102         5986 return $self;
53             }
54              
55             sub build_dynamic_lib_dist {
56 0     0 0 0 my ($self, $basic_type_name, $category) = @_;
57            
58             # Create the compiler
59 0         0 my $compiler = SPVM::Builder::Compiler->new(
60             include_dirs => $self->include_dirs
61             );
62            
63 0         0 my $success = $compiler->compile($basic_type_name, __FILE__, __LINE__);
64 0 0       0 unless ($success) {
65 0         0 $compiler->print_error_messages(*STDERR);
66 0         0 exit(255);
67             }
68 0         0 my $runtime = $compiler->get_runtime;
69 0         0 my $class_file = $runtime->get_class_file($basic_type_name);
70 0         0 my $method_names = $runtime->get_method_names($basic_type_name, $category);
71 0         0 my $precompile_source = $runtime->build_precompile_module_source($basic_type_name);
72 0         0 my $dl_func_list = SPVM::Builder::Util::create_dl_func_list($basic_type_name, $method_names, {category => $category});
73            
74 0         0 $self->build_dist($basic_type_name, {category => $category, class_file => $class_file, dl_func_list => $dl_func_list, precompile_source => $precompile_source});
75             }
76              
77             sub build_dist {
78 0     0 0 0 my ($self, $basic_type_name, $options) = @_;
79            
80 0   0     0 $options ||= {};
81            
82 0         0 my $build_dir = $self->build_dir;
83            
84 0         0 my $dl_func_list = $options->{dl_func_list};
85 0         0 my $class_file = $options->{class_file};
86 0         0 my $precompile_source = $options->{precompile_source};
87            
88 0         0 my $category = $options->{category};
89            
90 0         0 my $build_src_dir;
91 0 0       0 if ($category eq 'precompile') {
    0          
92 0         0 $build_src_dir = SPVM::Builder::Util::create_build_src_path($build_dir);
93 0         0 mkpath $build_src_dir;
94            
95 0         0 my $cc = SPVM::Builder::CC->new(
96             build_dir => $build_dir,
97             );
98            
99 0         0 $cc->build_precompile_module_source_file(
100             $basic_type_name,
101             {
102             output_dir => $build_src_dir,
103             precompile_source => $precompile_source,
104             class_file => $class_file,
105             }
106             );
107             }
108             elsif ($category eq 'native') {
109 0         0 $build_src_dir = 'lib';
110             }
111              
112 0         0 my $build_object_dir = SPVM::Builder::Util::create_build_object_path($build_dir);
113 0         0 mkpath $build_object_dir;
114            
115 0         0 my $build_lib_dir = 'blib/lib';
116            
117 0         0 $self->build(
118             $basic_type_name,
119             {
120             compile_input_dir => $build_src_dir,
121             compile_output_dir => $build_object_dir,
122             link_output_dir => $build_lib_dir,
123             category => $category,
124             class_file => $class_file,
125             dl_func_list => $dl_func_list,
126             }
127             );
128             }
129              
130             sub build_dynamic_lib_dist_precompile {
131 0     0 0 0 my ($self, $basic_type_name) = @_;
132            
133 0         0 $self->build_dynamic_lib_dist($basic_type_name, 'precompile');
134             }
135              
136             sub build_dynamic_lib_dist_native {
137 0     0 0 0 my ($self, $basic_type_name) = @_;
138            
139 0         0 $self->build_dynamic_lib_dist($basic_type_name, 'native');
140             }
141              
142             sub build_at_runtime {
143 341     341 0 1229 my ($self, $basic_type_name, $options) = @_;
144            
145 341   50     1250 $options ||= {};
146            
147 341         1723 my $build_dir = $self->build_dir;
148            
149 341         999 my $dl_func_list = $options->{dl_func_list};
150 341         777 my $class_file = $options->{class_file};
151 341         1264 my $precompile_source = $options->{precompile_source};
152              
153 341         941 my $category = $options->{category};
154            
155             # Build directory
156 341 50       1157 if (defined $build_dir) {
157 341         21753 mkpath $build_dir;
158             }
159             else {
160 0         0 confess "The \"build_dir\" field must be defined to build a $category method at runtime. Perhaps the setting of the SPVM_BUILD_DIR environment variable is forgotten";
161             }
162            
163             # Source directory
164 341         1363 my $build_src_dir;
165 341 100       1666 if ($category eq 'precompile') {
    50          
166 315         2297 $build_src_dir = SPVM::Builder::Util::create_build_src_path($build_dir);
167 315         9408 mkpath $build_src_dir;
168            
169 315         4595 my $cc = SPVM::Builder::CC->new(
170             build_dir => $build_dir,
171             at_runtime => 1,
172             );
173            
174 315         3132 $cc->build_precompile_module_source_file(
175             $basic_type_name,
176             {
177             output_dir => $build_src_dir,
178             precompile_source => $precompile_source,
179             class_file => $class_file,
180             }
181             );
182             }
183             elsif ($category eq 'native') {
184 26         103 my $class_file = $options->{class_file};
185 26         217 $build_src_dir = SPVM::Builder::Util::remove_basic_type_name_part_from_file($class_file, $basic_type_name);
186             }
187            
188             # Object directory
189 341         3197 my $build_object_dir = SPVM::Builder::Util::create_build_object_path($build_dir);
190 341         14868 mkpath $build_object_dir;
191            
192             # Lib directory
193 341         3305 my $build_lib_dir = SPVM::Builder::Util::create_build_lib_path($build_dir);
194 341         9178 mkpath $build_lib_dir;
195            
196 341         4661 my $build_file = $self->build(
197             $basic_type_name,
198             {
199             compile_input_dir => $build_src_dir,
200             compile_output_dir => $build_object_dir,
201             link_output_dir => $build_lib_dir,
202             category => $category,
203             class_file => $class_file,
204             dl_func_list => $dl_func_list,
205             at_runtime => 1,
206             }
207             );
208            
209 341         17080 return $build_file;
210             }
211              
212             sub build {
213 341     341 0 1349 my ($self, $basic_type_name, $options) = @_;
214            
215 341   50     1930 $options ||= {};
216            
217 341         1180 my $build_dir = $self->build_dir;
218            
219 341         1033 my $at_runtime = $options->{at_runtime};
220 341         2436 my $cc = SPVM::Builder::CC->new(
221             build_dir => $build_dir,
222             at_runtime => $at_runtime,
223             );
224            
225 341         988 my $dl_func_list = $options->{dl_func_list};
226            
227 341         849 my $category = $options->{category};
228            
229             # Class file
230 341         842 my $class_file = $options->{class_file};
231 341 50       1213 unless (defined $class_file) {
232 0         0 my $config_file = SPVM::Builder::Util::get_config_file_from_basic_type_name($basic_type_name);
233 0 0       0 if ($config_file) {
234 0         0 $class_file = $config_file;
235 0         0 $class_file =~ s/\.config$/\.spvm/;
236             }
237             else {
238 0         0 confess "The class file \"$class_file\" is not found";
239             }
240             }
241            
242 341         689 my $config;
243 341 100       1856 if ($category eq 'native') {
    50          
244 26         131 $config = $self->create_native_config_from_class_file($class_file);
245             }
246             elsif ($category eq 'precompile') {
247 315         2488 $config = SPVM::Builder::Util::API::create_default_config();
248             }
249            
250 341         2194 $config->class_name($basic_type_name);
251            
252             # Compile source file and create object files
253             my $compile_options = {
254             input_dir => $options->{compile_input_dir},
255             output_dir => $options->{compile_output_dir},
256 341         1959 config => $config,
257             category => $category,
258             };
259              
260 341         3088 my $object_files = $cc->compile_source_files($basic_type_name, $compile_options);
261            
262             # Link object files and create dynamic library
263             my $link_options = {
264             output_dir => $options->{link_output_dir},
265 341         7683 config => $config,
266             category => $category,
267             dl_func_list => $dl_func_list,
268             };
269 341         5223 my $output_file = $cc->link(
270             $basic_type_name,
271             $object_files,
272             $link_options
273             );
274            
275 341         52315 return $output_file;
276             }
277              
278             sub create_native_config_from_class_file {
279 27     27 0 102 my ($self, $class_file) = @_;
280            
281 27         66 my $config;
282 27         61 my $config_file = $class_file;
283 27         270 $config_file =~ s/\.spvm$/.config/;
284              
285             # Config file
286 27 50       755 if (-f $config_file) {
287 27         466 $config = SPVM::Builder::Config->load_config($config_file);
288             }
289             else {
290 0         0 my $error = $self->_error_message_find_config($config_file);
291 0         0 confess $error;
292             }
293            
294 27         87 return $config;
295             }
296              
297             sub _error_message_find_config {
298 0     0     my ($self, $config_file) = @_;
299            
300 0           my $error = <<"EOS";
301             Can't find the native config file \"$config_file\".
302              
303             The config file must contain at least the following code.
304             ----------------------------------------------
305             use strict;
306             use warnings;
307              
308             use SPVM::Builder::Config;
309             my \$config = SPVM::Builder::Config->new_gnu99(file => __FILE__);
310              
311             \$config;
312             ----------------------------------------------
313             EOS
314            
315             }
316              
317             1;
318              
319             =encoding utf8
320              
321             =head1 Name
322              
323             SPVM::Builder - Build Dynamic Libraries for SPVM Distribution
324              
325             =head1 Description
326              
327             The SPVM::Builder class has methods to build dynamic librares for a SPVM distribution.
328              
329             =head1 Copyright & License
330              
331             Copyright (c) 2023 Yuki Kimoto
332              
333             MIT License