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