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