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