If no compiler options are available, don't ask
[charm.git] / smart-build.pl
1 #!/usr/bin/perl
2
3
4 # This is an interactive script that knows
5 # common ways to build Charm++ and AMPI.
6 #
7 # Authors: dooley, becker
8
9
10 # Turn off I/O buffering
11 $| = 1;
12
13
14
15 # A subroutine that reads from input and returns a yes/no/default
16 sub promptUserYN {
17   while($line = <>){
18         chomp $line;
19         if(lc($line) eq "y" || lc($line) eq "yes" ){
20           return "yes";
21         } elsif(lc($line) eq "n" || lc($line) eq "no" ){
22           return "no";
23         } elsif( $line eq "" ){
24           return "default";
25         }
26   }
27 }
28   
29
30 # The beginning of the good stuff:
31 print "\n============================================================\n";
32 print "\nBegin interactive charm configuration ...\n";
33 print "If you are a poweruser expecting a list of options, please use ./build --help\n";
34 print "\n============================================================\n\n\n";
35
36
37
38 # check for MPI. 
39
40 $mpi_found = "false";
41 $m = system("which mpicc mpiCC > /dev/null 2>/dev/null") / 256;
42 if($m == 0){
43   $mpi_found = "true";
44 }
45 $m = system("which mpicc mpicxx > /dev/null 2>/dev/null") / 256;
46 if($m == 0){
47   $mpi_found = "true";
48 }
49
50
51 # Use uname to get the cpu type and OS information
52 $os = `uname -s`;
53 $cpu = `uname -m`;
54
55 #Variables to hold the portions of the configuration:
56 $nobs = "";
57 $arch = "";
58 $compilers = "";
59 $options = "";
60
61 #remove newlines from these strings:
62 chomp($os);
63 chomp ($cpu);
64
65
66 # Determine OS kernel
67 if ($os eq "Linux") {
68   $arch_os = "linux";
69 } elsif ($os eq "Darwin") {
70   $arch_os = "darwin";
71 } elsif ($os =~ m/BSD/ ) {
72   $arch_os = "linux";
73 } elsif ($os =~ m/OSF1/ ) {
74   $arch_os = "linux";
75 } elsif ($os =~ m/AIX/ ) {
76   $arch = "mpi-sp";
77 } elsif ($os =~ m/CYGWIN/ ) {
78   print "Detected a Cygwin system\n";
79   print "This uses the gnu compiler by default,\n";
80   print "To build with Microsoft Visual C++ compiler, use net-win32. Please refer to README.win32 for the details on setting up VC++ under cygwin.\n\n";
81   $arch_os = "cygwin";
82 }
83
84
85
86 # Determine architecture (x86, ppc, ...)
87 if($cpu =~ m/i[0-9]86/){
88   $x86 = 1;
89 } elsif($cpu =~ m/x86\_64/){
90   $amd64 = 1;
91 } elsif($cpu =~ m/ia64/){
92   $ia64 = 1;
93   $nobs = "--no-build-shared";
94 } elsif($cpu =~ m/powerpc/){
95   $ppc = 1;
96 } elsif($cpu =~ m/Power Mac/){
97   $ppc = 1;
98 } elsif($cpu =~ m/alpha/){
99   $alpha = 1;
100 }
101
102
103
104 # Determine converse architecture (net, mpi, ...)
105 print "Do you want to specify a multi-core version that runs only on a single multi-core node? [y/N]";
106 $multicore = promptUserYN();
107
108 if($multicore eq "true"){
109     $converse_network_type = "multicore";
110 }
111 else {
112
113 $skip_choosing = "false";
114
115 # default to net
116 $converse_network_type = "net";
117
118 # Give option of just using the mpi version if mpicc and mpiCC are found
119 if($mpi_found eq "true"){
120   print "\nI found that you have an mpicc available in your path.\nDo you want to build Charm++ on this MPI? [Y/n]: ";
121   $p = promptUserYN();
122   if($p eq "yes" || $p eq "default"){
123         $converse_network_type = "mpi";
124         $skip_choosing = "true";
125   }     
126 }
127
128 if($skip_choosing eq "false") { 
129   
130   print "\nDo you have a special network interconnect? [y/N]: ";
131   $p = promptUserYN();
132   if($p eq "yes"){
133         print << "EOF";
134         
135 Choose an interconnect from below: [1-11]
136          1) MPI
137          2) Infiniband (native ibverbs alpha version)
138          3) Myrinet GM
139          4) Myrinet MX
140          5) LAPI
141          6) Cray XT3, XT4 (not yet tested on CNL)
142          7) Bluegene/L Native (only at T. J. Watson)
143          8) Bluegene/L MPI
144          9) Bluegene/P Native (only at T. J. Watson)
145         10) Bluegene/P MPI
146         11) VMI
147
148 EOF
149         
150         while($line = <>){
151           chomp $line;
152           if($line eq "1"){
153                 $converse_network_type = "mpi";
154                 last;
155           } elsif($line eq "2"){
156                 $converse_network_type = "net";
157                 $options = "$options ibverbs ";
158                 last;
159           } elsif($line eq "3"){
160                 $converse_network_type = "net";
161                 $options = $options . "gm ";
162                 last;
163           } elsif($line eq "4"){
164                 $converse_network_type = "net";
165                 $options = $options . "mx ";
166                 last;
167           } elsif($line eq "5"){
168                 $arch = "lapi";
169                 last;
170           } elsif($line eq "6"){
171                 $arch = "mpi-crayxt3";
172                 last;
173           } elsif($line eq "7"){
174                 $arch = "bluegenel";
175                 $compilers = "xlc ";
176                 $nobs = "--no-build-shared";
177                 last;
178           } elsif($line eq "8"){
179                 $arch = "mpi-bluegenel";
180                 $compilers = "xlc ";
181                 $nobs = "--no-build-shared";
182                 last;
183           } elsif($line eq "9"){
184                 $arch = "bluegenep";
185                 $compilers = "xlc ";
186                 last;
187           } elsif($line eq "10"){
188                 $arch = "mpi-bluegenep";
189                 $compilers = "xlc ";
190                 last;
191           } elsif($line eq "11"){
192                 $converse_network_type = "vmi";
193                 last;
194           } else {
195                 print "Invalid option, please try again :P\n"
196           }
197         }       
198   }
199 }
200
201
202 # construct an $arch string if we did not explicitly set one above
203 if($arch eq ""){
204           $arch = "${converse_network_type}-${arch_os}";
205           if($amd64) {
206                 $arch = $arch . "-amd64";
207           } elsif($ia64){
208                 $arch = $arch . "-ia64";
209           } elsif($ppc){
210                 $arch = $arch . "-ppc";
211           } elsif($alpha){
212                 $arch = $arch . "-axp";
213           }
214 }
215   
216 # Fixup $arch to match the horrible
217 # inconsistent directories in src/archs
218
219 if($arch eq "net-darwin"){
220         $arch = "net-darwin-x86";
221 } elsif($arch eq "net-darwin-ppc"){
222         $arch = "net-ppc-darwin";
223 } elsif($arch eq "mpi-darwin-ppc"){
224         $arch = "mpi-ppc-darwin";
225
226
227
228
229 # Determine whether to support SMP / Multicore
230 print "\nDo you want SMP support? [y/N]";
231 $p = promptUserYN();
232 if($p eq "yes" ){
233   $options = "$options smp ";
234 }
235
236
237 }  # end of if multicore
238
239
240 #================ Choose Compiler =================================
241
242 # Lookup list of compilers
243 $cs = `./build charm++ $arch help | grep "Supported compilers"`;
244 # prune away beginning of the line
245 $cs =~ m/Supported compilers: (.*)/;
246 $cs = $1;
247 # split the line into an array
248 @c_list = split(" ", $cs);
249
250 # print list of compilers
251 $numc = @c_list;
252
253 if ($numc > 0) {
254     print "\nDo you want to specify a compiler? [y/N]";
255     $p = promptUserYN();
256     if($p eq "yes" ){
257         print "Choose a compiler: [1-$numc] \n";
258
259         $i = 1;
260         foreach $c (@c_list){
261             print "\t$i)\t$c\n";
262             $i++;
263         }
264
265         # Choose compiler
266         while($line = <>){
267             chomp $line;
268             if($line =~ m/([0-9]*)/ && $1 > 0 && $1 <= $numc){
269                 $compilers = $c_list[$1-1];
270                 last;
271             } else {
272                 print "Invalid option, please try again :P\n"
273             }
274         }
275     }
276 }
277
278
279
280 #================ Choose Options =================================
281
282 #Create a hash table containing descriptions of various options
283 %explanations = ();
284 $explanations{"ooc"} = "Out-of-core execution support in Charm++";
285 $explanations{"tcp"} = "Charm++ over TCP instead of UDP for net versions. TCP is slower";
286 $explanations{"ifort"} = "Use Intel's ifort fortran compiler";
287 $explanations{"gfortran"} = "Use gfortran compiler for fortran";
288 $explanations{"g95"} = "Use g95 compiler";
289 $explanations{"ifort"} = "Use Intel's ifort fortran compiler";
290 $explanations{"pgf90"} = "Use Portland Group's pgf90 fortran compiler";
291 $explanations{"ifc"} = "Use Intel's ifc compiler";
292 $explanations{"ammasso"} = "Use native RDMA support on Ammasso interconnect";
293 $explanations{"syncft"} = "Use initial fault tolerance support";
294
295
296
297 print "\nDo you want to specify any Charm++ build options such as fortran compilers? [y/N]";
298 $special_options = promptUserYN();
299
300 if($special_options eq "yes"){
301
302   # Produce list of options
303
304   $opts = `./build charm++ $arch help | grep "Supported options"`;
305   # prune away beginning of line
306   $opts =~ m/Supported options: (.*)/;
307   $opts = $1;
308
309   @option_list = split(" ", $opts);
310   
311   print "Please enter one or more numbers separated by spaces\n";
312   print "Choices:\n";
313
314   # Prune out entries that would already have been chosen above, such as smp
315   @option_list_pruned = ();
316   foreach $o (@option_list){
317         if($o ne "smp" && $o ne "ibverbs" && $o ne "gm" && $o ne "mx"){
318           @option_list_pruned = (@option_list_pruned , $o);
319         }
320   }
321
322   # sort the list
323   @option_list_pruned = sort @option_list_pruned;
324
325   # print out list for user to select from
326   $i = 1;
327   foreach $o (@option_list_pruned){
328         $exp = $explanations{$o};
329         print "\t$i)\t$o";
330         # pad whitespace before options
331         for($j=0;$j<20-length($o);$j++){
332           print " ";
333         }
334     print ": $exp";
335         print "\n";
336         $i++;
337   }
338   print "\t$i)\tNone Of The Above\n";
339
340   $num_options = @option_list_pruned;
341
342   while($line = <>){
343         chomp $line;
344     $line =~ m/([0-9 ]*)/;
345     @entries = split(" ",$1);
346     @entries = sort(@entries);
347
348         $additional_options = "";
349         foreach $e (@entries) {
350           if($e>=1 && $e<= $num_options){
351                 $estring = $option_list_pruned[$e-1];
352                 $additional_options = "$additional_options $estring";
353           } elsif ($e == $num_options+1){
354                 # user chose "None of the above"
355                 # clear the options we may have seen before
356                 $additional_options = " ";
357           }
358         }
359
360         # if the user input something reasonable, we can break out of this loop
361         if($additional_options ne ""){
362           $options = "$options ${additional_options} ";
363           last;
364         }
365
366   }
367
368 }
369
370
371
372
373 # Choose compiler flags
374 print << "EOF";
375         
376 Choose a set of compiler flags [1-5]
377         1) none
378         2) debug
379         3) optimized [default]
380         4) optimized + projections
381         5) custom
382         
383 EOF
384
385 $compiler_flags = "";
386
387 while($line = <>){
388         chomp $line;
389         if($line eq "1"){
390                 last;
391         } elsif($line eq "2"){
392                 $compiler_flags = "-g -O0";
393                 last;
394         } elsif($line eq "3" || $line eq ""){
395                 $compiler_flags = "-O2 -DCMK_OPTIMIZE";
396                 last;
397         } elsif($line eq "4"){ 
398                 $compiler_flags = "-O2"; 
399                 last; 
400         }  elsif($line eq "5"){
401
402                 print "Enter compiler options: ";
403                 $input_line = <>;
404                 chomp($input_line);
405                 $compiler_flags = $input_line;
406                 
407                 last;
408         } else {
409                 print "Invalid option, please try again :P\n"
410         }
411 }
412
413
414
415
416 # Determine the target to build.
417 # We want this simple so we just give 2 options
418 $target = "";
419
420 print << "EOF";
421
422 What do you want to build?
423         1) Charm++ [default] (choose this if you are building NAMD)
424         2) Charm++, AMPI, ParFUM, FEM and other libraries
425
426 EOF
427
428 while($line = <>){
429         chomp $line;
430         if($line eq "1" || $line eq ""){
431                 $target = "charm++";
432                 last;
433         } elsif($line eq "2"){
434                 $target = "LIBS";
435                 last;
436         } else {
437                 print "Invalid option, please try again :P\n"
438         }
439         
440 }
441
442 # Determine whether to use a -j4 flag for faster building
443 # Currently LIBS cannot be safely built with -j4
444 $j = "";
445 if($target eq "charm++"){
446         print "\nDo you want to do a parallel build (-j4)?[Y/n]";
447         $p = promptUserYN();
448         if($p eq "yes" || $p eq "default"){
449           $j = "-j4";
450         }
451 }
452
453
454 # Compose the build line
455 $build_line = "./build $target $arch $compilers $options $smp $j ${compiler_flags}\n";
456
457
458 # Save the build line in the log
459 open(BUILDLINE, ">>smart-build.log");
460 print BUILDLINE `date`;
461 print BUILDLINE "Using the following build command:\n";
462 print BUILDLINE "$build_line\n";
463 close(BUILDLINE);
464
465
466 print "We have determined a suitable build line is:\n";
467 print "\t$build_line\n\n";
468
469
470 # Execute the build line if the appropriate architecture directory exists
471 print "Do you want to start the build now? [Y/n]";
472 $p = promptUserYN();
473 if($p eq "yes" || $p eq "default"){
474   if(-e "src/arch/$arch"){
475         print "Building with: ${build_line}\n"; 
476         # Execute the build line
477         system($build_line);
478   } else {
479         print "We could not figure out how to build charm with those options on this platform, please manually build\n";
480         print "Try something similar to: ${build_line}\n";
481   }
482 }
483
484
485