3b2fe59fc10dd38e5bfd06f03884b8615375eec5
[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/ppc*/){
85   $ppc = 1;
86 } elsif($cpu =~ m/alpha/){
87   $alpha = 1;
88 }
89
90
91
92 # default to net
93 $converse_network_type = "net";
94
95
96 # check for MPI
97
98 $skip_choosing = "false";
99
100 $mpi_found = "false";
101 $m = system("which mpicc mpiCC > /dev/null 2>/dev/null") / 256;
102 if($m == 0){
103     $mpi_found = "true";
104     $mpioption = "";
105 }
106 $m = system("which mpicc mpicxx > /dev/null 2>/dev/null") / 256;
107 if($m == 0){
108     $mpi_found = "true";
109     $mpioption = "mpicxx";
110 }
111
112 # Give option of just using the mpi version if mpicc and mpiCC are found
113 if($mpi_found eq "true"){
114   print "\nI found that you have an mpicc available in your path.\nDo you want to build Charm++ on this MPI? [y/N]: ";
115   $p = promptUserYN();
116   if($p eq "yes"){
117         $converse_network_type = "mpi";
118         $skip_choosing = "true";
119         $options = "$options $mpioption";
120   }     
121 }
122
123 if($skip_choosing eq "false") { 
124   
125   print "\nDo you have a special network interconnect? [y/N]: ";
126   $p = promptUserYN();
127   if($p eq "yes"){
128         print << "EOF";
129         
130 Choose an interconnect from below: [1-11]
131          1) MPI
132          2) Infiniband (native ibverbs alpha version)
133          3) Myrinet GM
134          4) Myrinet MX
135          5) LAPI
136          6) Cray XT3, XT4
137          7) Cray XT5
138          8) Bluegene/L Native (only at T. J. Watson)
139          9) Bluegene/L MPI
140         10) Bluegene/P Native
141         11) Bluegene/P MPI
142         12) VMI
143
144 EOF
145         
146         while($line = <>){
147           chomp $line;
148           if($line eq "1"){
149                 $converse_network_type = "mpi";
150                 last;
151           } elsif($line eq "2"){
152                 $converse_network_type = "net";
153                 $options = "$options ibverbs ";
154                 last;
155           } elsif($line eq "3"){
156                 $converse_network_type = "net";
157                 $options = $options . "gm ";
158                 last;
159           } elsif($line eq "4"){
160                 $converse_network_type = "net";
161                 $options = $options . "mx ";
162                 last;
163           } elsif($line eq "5"){
164                 $arch = "lapi";
165                 last;
166           } elsif($line eq "6"){
167                 $arch = "mpi-crayxt3";
168                 last;
169           } elsif($line eq "7"){
170                 $arch = "mpi-crayxt";
171                 last;
172           } elsif($line eq "8"){
173                 $arch = "bluegenel";
174                 $compilers = "xlc ";
175                 $nobs = "--no-build-shared";
176                 last;
177           } elsif($line eq "9"){
178                 $arch = "mpi-bluegenel";
179                 $compilers = "xlc ";
180                 $nobs = "--no-build-shared";
181                 last;
182           } elsif($line eq "10"){
183                 $arch = "bluegenep";
184                 $compilers = "xlc ";
185                 last;
186           } elsif($line eq "11"){
187                 $arch = "mpi-bluegenep";
188                 $compilers = "xlc ";
189                 last;
190           } elsif($line eq "12"){
191                 $converse_network_type = "vmi";
192                 last;
193           } else {
194                 print "Invalid option, please try again :P\n"
195           }
196         }       
197   }
198 }
199
200
201 # construct an $arch string if we did not explicitly set one above
202 if($arch eq ""){
203   $arch = "${converse_network_type}-${arch_os}";
204           if($amd64) {
205                 $arch = $arch . "-x86_64";
206           } elsif($ia64){
207                 $arch = $arch . "-ia64";
208           } elsif($ppc){
209                 $arch = $arch . "-ppc";
210           } elsif($alpha){
211                 $arch = $arch . "-axp";
212           }
213 }
214   
215 # Fixup $arch to match the inconsistent directories in src/archs
216
217 if($arch eq "net-darwin"){
218         $arch = "net-darwin-x86";
219 } elsif($arch eq "net-ppc-darwin"){
220         $arch = "net-darwin-ppc";
221 } elsif($arch eq "mpi-ppc-darwin"){
222         $arch = "mpi-darwin-ppc";
223 } elsif($arch eq "multicore-linux-x86_64"){
224         $arch = "multicore-linux64";
225
226
227
228
229
230
231 #================ Choose SMP/PXSHM =================================
232
233 # find what options are available
234 $opts = `./build charm++ $arch help 2>&1 | grep "Supported options"`;
235 $opts =~ m/Supported options: (.*)/;
236 $opts = $1;
237
238
239 #always provide multicore and single-threaded versions
240 print << "EOF";
241 How do you want to handle SMP/Multicore: [1-4]
242          1) single-threaded [default]
243          2) multicore(single node only)
244 EOF
245
246 # only add the smp or pxshm options if they are available
247 $counter = 3; # the next index used in the list
248
249 $smpIndex = -1;
250 if($opts =~ m/smp/){
251   print "         $counter) SMP\n";
252   $smpIndex = $counter; 
253   $counter ++;
254 }
255
256 $pxshmIndex = -1;
257 if($opts =~ m/pxshm/){
258   print "         $counter) POSIX Shared Memory\n";
259   $pxshmIndex = $counter; 
260   $counter ++;
261 }
262
263 while($line = <>){
264         chomp $line;
265         if($line eq "1" || $line eq ""){
266             last;
267         } elsif($line eq "2"){
268             $converse_network_type = "multicore";
269             last;
270         } elsif($line eq $smpIndex){
271             $options = "$options smp ";
272             last;
273         } elsif($line eq $pxshmIndex){
274             $options = "$options pxshm ";
275             last;
276         }
277 }
278
279
280
281
282
283
284
285 #================ Choose Compiler =================================
286
287 # Lookup list of compilers
288 $cs = `./build charm++ $arch help 2>&1 | grep "Supported compilers"`;
289 # prune away beginning of the line
290 $cs =~ m/Supported compilers: (.*)/;
291 $cs = $1;
292 # split the line into an array
293 @c_list = split(" ", $cs);
294
295 # print list of compilers
296 $numc = @c_list;
297
298 if ($numc > 0) {
299     print "\nDo you want to specify a compiler? [y/N]";
300     $p = promptUserYN();
301     if($p eq "yes" ){
302         print "Choose a compiler: [1-$numc] \n";
303
304         $i = 1;
305         foreach $c (@c_list){
306             print "\t$i)\t$c\n";
307             $i++;
308         }
309
310         # Choose compiler
311         while($line = <>){
312             chomp $line;
313             if($line =~ m/([0-9]*)/ && $1 > 0 && $1 <= $numc){
314                 $compilers = $c_list[$1-1];
315                 last;
316             } else {
317                 print "Invalid option, please try again :P\n"
318             }
319         }
320     }
321 }
322
323
324
325
326 #================ Choose Options =================================
327
328 #Create a hash table containing descriptions of various options
329 %explanations = ();
330 $explanations{"ooc"} = "Out-of-core execution support in Charm++";
331 $explanations{"tcp"} = "Charm++ over TCP instead of UDP for net versions. TCP is slower";
332 $explanations{"ifort"} = "Use Intel's ifort fortran compiler";
333 $explanations{"gfortran"} = "Use gfortran compiler for fortran";
334 $explanations{"g95"} = "Use g95 compiler";
335 $explanations{"ifort"} = "Use Intel's ifort fortran compiler";
336 $explanations{"pgf90"} = "Use Portland Group's pgf90 fortran compiler";
337 $explanations{"ifc"} = "Use Intel's ifc compiler";
338 $explanations{"ammasso"} = "Use native RDMA support on Ammasso interconnect";
339 $explanations{"syncft"} = "Use initial fault tolerance support";
340 $explanations{"mlogft"} = "Use message logging fault tolerance support";
341
342
343
344
345
346   # Produce list of options
347
348   $opts = `./build charm++ $arch help 2>&1 | grep "Supported options"`;
349   # prune away beginning of line
350   $opts =~ m/Supported options: (.*)/;
351   $opts = $1;
352
353   @option_list = split(" ", $opts);
354   
355
356   # Prune out entries that would already have been chosen above, such as smp
357   @option_list_pruned = ();
358   foreach $o (@option_list){
359         if($o ne "smp" && $o ne "ibverbs" && $o ne "gm" && $o ne "mx"){
360           @option_list_pruned = (@option_list_pruned , $o);
361         }
362   }
363
364   # sort the list
365   @option_list_pruned = sort @option_list_pruned;
366   if (@option_list_pruned > 0) {
367
368       print "\nDo you want to specify any Charm++ build options, such as fortran compilers? [y/N]";
369       $special_options = promptUserYN();
370
371       if($special_options eq "yes"){
372
373           # print out list for user to select from
374           print "Please enter one or more numbers separated by spaces\n";
375           print "Choices:\n";
376           $i = 1;
377           foreach $o (@option_list_pruned){
378               $exp = $explanations{$o};
379               print "\t$i)\t$o";
380               # pad whitespace before options
381               for($j=0;$j<20-length($o);$j++){
382                   print " ";
383               }
384               print ": $exp";
385               print "\n";
386               $i++;
387           }
388           print "\t$i)\tNone Of The Above\n";
389
390           $num_options = @option_list_pruned;
391
392           while($line = <>){
393               chomp $line;
394               $line =~ m/([0-9 ]*)/;
395               @entries = split(" ",$1);
396               @entries = sort(@entries);
397
398               $additional_options = "";
399               foreach $e (@entries) {
400                   if($e>=1 && $e<= $num_options){
401                       $estring = $option_list_pruned[$e-1];
402                       $additional_options = "$additional_options $estring";
403                   } elsif ($e == $num_options+1){
404                       # user chose "None of the above"
405                       # clear the options we may have seen before
406                       $additional_options = " ";
407                   }
408               }
409
410               # if the user input something reasonable, we can break out of this loop
411               if($additional_options ne ""){
412                   $options = "$options ${additional_options} ";
413                   last;
414               }
415
416           }
417       }
418   }
419
420
421
422
423
424
425
426
427
428 # Choose compiler flags
429 print << "EOF";
430         
431 Choose a set of compiler flags [1-5]
432         1) none
433         2) debug                      -g -O0
434         3) optimized [default]        -O2
435         4) optimized no projections   -O2 -DCMK_OPTIMIZE
436         5) custom
437         
438 EOF
439
440 $compiler_flags = "";
441
442 while($line = <>){
443         chomp $line;
444         if($line eq "1"){
445                 last;
446         } elsif($line eq "2"){
447                 $compiler_flags = "-g -O0";
448                 last;
449         } elsif($line eq "4" ){
450                 $compiler_flags = "-O2 -DCMK_OPTIMIZE";
451                 last;
452         } elsif($line eq "3" || $line eq ""){ 
453                 $compiler_flags = "-O2"; 
454                 last; 
455         }  elsif($line eq "5"){
456
457                 print "Enter compiler options: ";
458                 $input_line = <>;
459                 chomp($input_line);
460                 $compiler_flags = $input_line;
461                 
462                 last;
463         } else {
464                 print "Invalid option, please try again :P\n"
465         }
466 }
467
468
469
470
471 # Determine the target to build.
472 # We want this simple so we just give 2 options
473 $target = "";
474
475 print << "EOF";
476
477 What do you want to build?
478         1) Charm++ [default] (choose this if you are building NAMD)
479         2) Charm++, AMPI, ParFUM, FEM and other libraries
480
481 EOF
482
483 while($line = <>){
484         chomp $line;
485         if($line eq "1" || $line eq ""){
486                 $target = "charm++";
487                 last;
488         } elsif($line eq "2"){
489                 $target = "LIBS";
490                 last;
491         } else {
492                 print "Invalid option, please try again :P\n"
493         }
494         
495 }
496
497 # Determine whether to use a -j flag for faster building
498 $j = "";
499     print << "EOF";
500     
501 Do you want to compile in parallel?
502         1) No
503         2) Build with -j2
504         3) Build with -j4
505         4) Build with -j8 
506         5) Build with -j16 [default]
507         6) Build with -j32
508         7) Build with -j
509
510 EOF
511
512     while($line = <>) {
513         chomp $line;
514         if($line eq "1"){
515             $j = "";
516             last;
517         } elsif($line eq "2") {
518             $j = "-j2";
519             last; 
520         } elsif($line eq "3") {
521             $j = "-j4";
522             last;
523         }  elsif($line eq "4") {
524             $j = "-j8";
525             last;
526         }  elsif($line eq "5" || $line eq "") {
527             $j = "-j16";
528             last;
529         }  elsif($line eq "6") {
530             $j = "-j32";
531             last;
532         }  elsif($line eq "7") {
533             $j = "-j";
534             last;
535         }   else {
536             print "Invalid option, please try again :P\n";
537         }
538 }
539
540
541 # Compose the build line
542 $build_line = "./build $target $arch $compilers $options $smp $j $nobs ${compiler_flags}\n";
543
544
545 # Save the build line in the log
546 open(BUILDLINE, ">>smart-build.log");
547 print BUILDLINE `date`;
548 print BUILDLINE "Using the following build command:\n";
549 print BUILDLINE "$build_line\n";
550 close(BUILDLINE);
551
552
553 print "We have determined a suitable build line is:\n";
554 print "\t$build_line\n\n";
555
556
557 # Execute the build line if the appropriate architecture directory exists
558 print "Do you want to start the build now? [Y/n]";
559 $p = promptUserYN();
560 if($p eq "yes" || $p eq "default"){
561   if(-e "src/arch/$arch"){
562         print "Building with: ${build_line}\n"; 
563         # Execute the build line
564         system($build_line);
565   } else {
566         print "We could not figure out how to build charm with those options on this platform, please manually build\n";
567         print "Try something similar to: ${build_line}\n";
568   }
569 }
570
571
572