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