]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | # Support for the Message Passing Interface (MPI) |
2 | # | |
3 | # (C) Copyright 2005, 2006 Trustees of Indiana University | |
4 | # (C) Copyright 2005 Douglas Gregor | |
5 | # | |
6 | # Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) | |
8 | # | |
9 | # Authors: Douglas Gregor | |
10 | # Andrew Lumsdaine | |
11 | # | |
12 | # ==== MPI Configuration ==== | |
13 | # | |
14 | # For many users, MPI support can be enabled simply by adding the following | |
15 | # line to your user-config.jam file: | |
16 | # | |
17 | # using mpi ; | |
18 | # | |
19 | # This should auto-detect MPI settings based on the MPI wrapper compiler in | |
20 | # your path, e.g., "mpic++". If the wrapper compiler is not in your path, or | |
21 | # has a different name, you can pass the name of the wrapper compiler as the | |
22 | # first argument to the mpi module: | |
23 | # | |
24 | # using mpi : /opt/mpich2-1.0.4/bin/mpiCC ; | |
25 | # | |
26 | # If your MPI implementation does not have a wrapper compiler, or the MPI | |
27 | # auto-detection code does not work with your MPI's wrapper compiler, | |
28 | # you can pass MPI-related options explicitly via the second parameter to the | |
29 | # mpi module: | |
30 | # | |
31 | # using mpi : : <find-shared-library>lammpio <find-shared-library>lammpi++ | |
32 | # <find-shared-library>mpi <find-shared-library>lam | |
33 | # <find-shared-library>dl ; | |
34 | # | |
35 | # To see the results of MPI auto-detection, pass "--debug-configuration" on | |
36 | # the bjam command line. | |
37 | # | |
38 | # The (optional) fourth argument configures Boost.MPI for running | |
39 | # regression tests. These parameters specify the executable used to | |
40 | # launch jobs (default: "mpirun") followed by any necessary arguments | |
41 | # to this to run tests and tell the program to expect the number of | |
42 | # processors to follow (default: "-np"). With the default parameters, | |
43 | # for instance, the test harness will execute, e.g., | |
44 | # | |
45 | # mpirun -np 4 all_gather_test | |
46 | # | |
47 | # ==== Linking Against the MPI Libraries === | |
48 | # | |
49 | # To link against the MPI libraries, import the "mpi" module and add the | |
50 | # following requirement to your target: | |
51 | # | |
52 | # <library>/mpi//mpi | |
53 | # | |
54 | # Since MPI support is not always available, you should check | |
55 | # "mpi.configured" before trying to link against the MPI libraries. | |
56 | ||
57 | import "class" : new ; | |
58 | import common ; | |
59 | import feature : feature ; | |
60 | import generators ; | |
61 | import os ; | |
62 | import project ; | |
63 | import property ; | |
64 | import testing ; | |
65 | import toolset ; | |
66 | import type ; | |
67 | import path ; | |
68 | ||
69 | # Make this module a project | |
70 | project.initialize $(__name__) ; | |
71 | project mpi ; | |
72 | ||
73 | if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] | |
74 | { | |
75 | .debug-configuration = true ; | |
76 | } | |
77 | ||
78 | # Assuming the first part of the command line is the given prefix | |
79 | # followed by some non-empty value, remove the first argument. Returns | |
80 | # either nothing (if there was no prefix or no value) or a pair | |
81 | # | |
82 | # <name>value rest-of-cmdline | |
83 | # | |
84 | # This is a subroutine of cmdline_to_features | |
85 | rule add_feature ( prefix name cmdline ) | |
86 | { | |
87 | local match = [ MATCH "^$(prefix)([^\" ]+|\"[^\"]+\") *(.*)$" : $(cmdline) ] ; | |
88 | ||
89 | # If there was no value associated with the prefix, abort | |
90 | if ! $(match) { | |
91 | return ; | |
92 | } | |
93 | ||
94 | local value = $(match[1]) ; | |
95 | ||
96 | if [ MATCH " +" : $(value) ] { | |
97 | value = "\"$(value)\"" ; | |
98 | } | |
99 | ||
100 | return "<$(name)>$(value)" $(match[2]) ; | |
101 | } | |
102 | ||
103 | # Strip any end-of-line characters off the given string and return the | |
104 | # result. | |
105 | rule strip-eol ( string ) | |
106 | { | |
107 | local match = [ MATCH "^(([A-Za-z0-9~`\.!@#$%^&*()_+={};:'\",.<>/?\\| -]|[|])*).*$" : $(string) ] ; | |
108 | ||
109 | if $(match) | |
110 | { | |
111 | return $(match[1]) ; | |
112 | } | |
113 | else | |
114 | { | |
115 | return $(string) ; | |
116 | } | |
117 | } | |
118 | ||
119 | # Split a command-line into a set of features. Certain kinds of | |
120 | # compiler flags are recognized (e.g., -I, -D, -L, -l) and replaced | |
121 | # with their Boost.Build equivalents (e.g., <include>, <define>, | |
122 | # <library-path>, <find-library>). All other arguments are introduced | |
123 | # using the features in the unknown-features parameter, because we | |
124 | # don't know how to deal with them. For instance, if your compile and | |
125 | # correct. The incoming command line should be a string starting with | |
126 | # an executable (e.g., g++ -I/include/path") and may contain any | |
127 | # number of command-line arguments thereafter. The result is a list of | |
128 | # features corresponding to the given command line, ignoring the | |
129 | # executable. | |
130 | rule cmdline_to_features ( cmdline : unknown-features ? ) | |
131 | { | |
132 | local executable ; | |
133 | local features ; | |
134 | local otherflags ; | |
135 | local result ; | |
136 | ||
137 | unknown-features ?= <cxxflags> <linkflags> ; | |
138 | ||
139 | # Pull the executable out of the command line. At this point, the | |
140 | # executable is just thrown away. | |
141 | local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" : $(cmdline) ] ; | |
142 | executable = $(match[1]) ; | |
143 | cmdline = $(match[2]) ; | |
144 | ||
145 | # List the prefix/feature pairs that we will be able to transform. | |
146 | # Every kind of parameter not mentioned here will be placed in both | |
147 | # cxxflags and linkflags, because we don't know where they should go. | |
148 | local feature_kinds-D = "define" ; | |
149 | local feature_kinds-I = "include" ; | |
150 | local feature_kinds-L = "library-path" ; | |
151 | local feature_kinds-l = "find-shared-library" ; | |
152 | ||
153 | while $(cmdline) { | |
154 | ||
155 | # Check for one of the feature prefixes we know about. If we | |
156 | # find one (and the associated value is nonempty), convert it | |
157 | # into a feature. | |
158 | local match = [ MATCH "^(-.)(.*)" : $(cmdline) ] ; | |
159 | local matched ; | |
160 | if $(match) && $(match[2]) { | |
161 | local prefix = $(match[1]) ; | |
162 | if $(feature_kinds$(prefix)) { | |
163 | local name = $(feature_kinds$(prefix)) ; | |
164 | local add = [ add_feature $(prefix) $(name) $(cmdline) ] ; | |
165 | ||
166 | if $(add) { | |
167 | ||
168 | if $(add[1]) = <find-shared-library>pthread | |
169 | { | |
170 | # Uhm. It's not really nice that this MPI implementation | |
171 | # uses -lpthread as opposed to -pthread. We do want to | |
172 | # set <threading>multi, instead of -lpthread. | |
173 | result += "<threading>multi" ; | |
174 | MPI_EXTRA_REQUIREMENTS += "<threading>multi" ; | |
175 | } | |
176 | else | |
177 | { | |
178 | result += $(add[1]) ; | |
179 | } | |
180 | ||
181 | cmdline = $(add[2]) ; | |
182 | matched = yes ; | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | # If we haven't matched a feature prefix, just grab the command-line | |
188 | # argument itself. If we can map this argument to a feature | |
189 | # (e.g., -pthread -> <threading>multi), then do so; otherwise, | |
190 | # and add it to the list of "other" flags that we don't | |
191 | # understand. | |
192 | if ! $(matched) { | |
193 | match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" : $(cmdline) ] ; | |
194 | local value = $(match[1]) ; | |
195 | cmdline = $(match[2]) ; | |
196 | ||
197 | # Check for multithreading support | |
198 | if $(value) = "-pthread" || $(value) = "-pthreads" | |
199 | { | |
200 | result += "<threading>multi" ; | |
201 | ||
202 | # DPG: This is a hack intended to work around a BBv2 bug where | |
203 | # requirements propagated from libraries are not checked for | |
204 | # conflicts when BBv2 determines which "common" properties to | |
205 | # apply to a target. In our case, the <threading>single property | |
206 | # gets propagated from the common properties to Boost.MPI | |
207 | # targets, even though <threading>multi is in the usage | |
208 | # requirements of <library>/mpi//mpi. | |
209 | MPI_EXTRA_REQUIREMENTS += "<threading>multi" ; | |
210 | } | |
211 | else if [ MATCH "(.*[a-zA-Z0-9<>?-].*)" : $(value) ] { | |
212 | otherflags += $(value) ; | |
213 | } | |
214 | } | |
215 | } | |
216 | ||
217 | # If there are other flags that we don't understand, add them to the | |
218 | # result as both <cxxflags> and <linkflags> | |
219 | if $(otherflags) { | |
220 | for unknown in $(unknown-features) | |
221 | { | |
222 | result += "$(unknown)$(otherflags:J= )" ; | |
223 | } | |
224 | } | |
225 | ||
226 | return $(result) ; | |
227 | } | |
228 | ||
229 | # Determine if it is safe to execute the given shell command by trying | |
230 | # to execute it and determining whether the exit code is zero or | |
231 | # not. Returns true for an exit code of zero, false otherwise. | |
232 | local rule safe-shell-command ( cmdline ) | |
233 | { | |
234 | local result = [ SHELL "$(cmdline) > /dev/null 2>/dev/null; if [ "$?" -eq "0" ]; then echo SSCOK; fi" ] ; | |
235 | return [ MATCH ".*(SSCOK).*" : $(result) ] ; | |
236 | } | |
237 | ||
238 | # Initialize the MPI module. | |
239 | rule init ( mpicxx ? : options * : mpirun-with-options * ) | |
240 | { | |
241 | if ! $(options) && $(.debug-configuration) | |
242 | { | |
243 | ECHO "===============MPI Auto-configuration===============" ; | |
244 | } | |
245 | ||
246 | if ! $(mpicxx) && [ os.on-windows ] | |
247 | { | |
248 | # Paths for Microsoft MPI | |
249 | local ms_mpi_path_native = "C:\\Program Files\\Microsoft MPI" ; | |
250 | local ms_mpi_sdk_path_native = "C:\\Program Files (x86)\\Microsoft SDKs\\MPI" ; | |
251 | ||
252 | # Path for Microsoft Compute Cluster Pack | |
253 | local cluster_pack_path_native = "C:\\Program Files\\Microsoft Compute Cluster Pack" ; | |
254 | ||
255 | # Try to auto-configure Microsoft MPI | |
256 | if [ GLOB $(ms_mpi_path_native)\\Bin : mpiexec.exe ] && | |
257 | [ GLOB $(ms_mpi_sdk_path_native)\\Include : mpi.h ] | |
258 | { | |
259 | if $(.debug-configuration) | |
260 | { | |
261 | ECHO "Found Microsoft MPI: $(ms_mpi_path_native)" ; | |
262 | ECHO "Found Microsoft MPI SDK: $(ms_mpi_sdk_path_native)" ; | |
263 | } | |
264 | ||
265 | local ms_mpi_sdk_path = [ path.make $(ms_mpi_sdk_path_native) ] ; | |
266 | ||
267 | # Pick up either the 32-bit or 64-bit library, depending on which address | |
268 | # model the user has selected. Default to 32-bit. | |
269 | options = <include>$(ms_mpi_sdk_path)/Include | |
270 | <address-model>64:<library-path>$(ms_mpi_sdk_path)/Lib/x64 | |
271 | <library-path>$(ms_mpi_sdk_path)/Lib/x86 | |
272 | <find-static-library>msmpi | |
273 | <toolset>msvc:<define>_SECURE_SCL=0 | |
274 | ; | |
275 | ||
276 | # Setup the "mpirun" equivalent (mpiexec) | |
277 | .mpirun = "\"$(ms_mpi_path_native)\\Bin\\mpiexec.exe"\" ; | |
278 | .mpirun_flags = -n ; | |
279 | } | |
280 | # Try to auto-configure to the Microsoft Compute Cluster Pack | |
281 | else if [ GLOB $(cluster_pack_path_native)\\Include : mpi.h ] | |
282 | { | |
283 | if $(.debug-configuration) | |
284 | { | |
285 | ECHO "Found Microsoft Compute Cluster Pack: $(cluster_pack_path_native)" ; | |
286 | } | |
287 | ||
288 | local cluster_pack_path = [ path.make $(cluster_pack_path_native) ] ; | |
289 | ||
290 | # Pick up either the 32-bit or 64-bit library, depending on which address | |
291 | # model the user has selected. Default to 32-bit. | |
292 | options = <include>$(cluster_pack_path)/Include | |
293 | <address-model>64:<library-path>$(cluster_pack_path)/Lib/amd64 | |
294 | <library-path>$(cluster_pack_path)/Lib/i386 | |
295 | <find-static-library>msmpi | |
296 | <toolset>msvc:<define>_SECURE_SCL=0 | |
297 | ; | |
298 | ||
299 | # Setup the "mpirun" equivalent (mpiexec) | |
300 | .mpirun = "\"$(cluster_pack_path_native)\\Bin\\mpiexec.exe"\" ; | |
301 | .mpirun_flags = -n ; | |
302 | } | |
303 | else if $(.debug-configuration) | |
304 | { | |
305 | ECHO "Did not find Microsoft MPI in $(ms_mpi_path_native)" ; | |
306 | ECHO " and/or Microsoft MPI SDK in $(ms_mpi_sdk_path_native)." ; | |
307 | ECHO "Did not find Microsoft Compute Cluster Pack in $(cluster_pack_path_native)." ; | |
308 | } | |
309 | } | |
310 | ||
311 | if ! $(options) | |
312 | { | |
313 | # Try to auto-detect options based on the wrapper compiler | |
314 | local command = [ common.get-invocation-command mpi : mpic++ : $(mpicxx) ] ; | |
315 | ||
316 | if ! $(mpicxx) && ! $(command) | |
317 | { | |
318 | # Try "mpiCC", which is used by MPICH | |
319 | command = [ common.get-invocation-command mpi : mpiCC ] ; | |
320 | } | |
321 | ||
322 | if ! $(mpicxx) && ! $(command) | |
323 | { | |
324 | # Try "mpicxx", which is used by OpenMPI and MPICH2 | |
325 | command = [ common.get-invocation-command mpi : mpicxx ] ; | |
326 | } | |
327 | ||
328 | if ! $(mpicxx) && ! $(command) | |
329 | { | |
330 | # Try "CC", which is used by Cray | |
331 | command = [ common.get-invocation-command mpi : CC ] ; | |
332 | } | |
333 | ||
334 | local result ; | |
335 | local compile_flags ; | |
336 | local link_flags ; | |
337 | ||
338 | if ! $(command) | |
339 | { | |
340 | # Do nothing: we'll complain later | |
341 | } | |
342 | # OpenMPI and newer versions of LAM-MPI have -showme:compile and | |
343 | # -showme:link. | |
344 | else if [ safe-shell-command "$(command) -showme:compile" ] && | |
345 | [ safe-shell-command "$(command) -showme:link" ] | |
346 | { | |
347 | if $(.debug-configuration) | |
348 | { | |
349 | ECHO "Found recent LAM-MPI or Open MPI wrapper compiler: $(command)" ; | |
350 | } | |
351 | ||
352 | compile_flags = [ SHELL "$(command) -showme:compile" ] ; | |
353 | link_flags = [ SHELL "$(command) -showme:link" ] ; | |
354 | ||
355 | # Prepend COMPILER as the executable name, to match the format of | |
356 | # other compilation commands. | |
357 | compile_flags = "COMPILER $(compile_flags) -DOMPI_SKIP_MPICXX " ; | |
358 | link_flags = "COMPILER $(link_flags)" ; | |
359 | } | |
360 | # Look for LAM-MPI's -showme | |
361 | else if [ safe-shell-command "$(command) -showme" ] | |
362 | { | |
363 | if $(.debug-configuration) | |
364 | { | |
365 | ECHO "Found older LAM-MPI wrapper compiler: $(command)" ; | |
366 | } | |
367 | ||
368 | result = [ SHELL "$(command) -showme" ] ; | |
369 | } | |
370 | # Look for MPICH | |
371 | else if [ safe-shell-command "$(command) -show" ] | |
372 | { | |
373 | if $(.debug-configuration) | |
374 | { | |
375 | ECHO "Found MPICH wrapper compiler: $(command)" ; | |
376 | } | |
377 | compile_flags = [ SHELL "$(command) -compile_info" ] ; | |
378 | link_flags = [ SHELL "$(command) -link_info" ] ; | |
379 | } | |
380 | # Sun HPC and Ibm POE | |
381 | else if [ SHELL "$(command) -v 2>/dev/null" ] | |
382 | { | |
383 | compile_flags = [ SHELL "$(command) -c -v -xtarget=native64 2>/dev/null" ] ; | |
384 | ||
385 | local back = [ MATCH "--------------------(.*)" : $(compile_flags) ] ; | |
386 | if $(back) | |
387 | { | |
388 | # Sun HPC | |
389 | if $(.debug-configuration) | |
390 | { | |
391 | ECHO "Found Sun MPI wrapper compiler: $(command)" ; | |
392 | } | |
393 | ||
394 | compile_flags = [ MATCH "(.*)--------------------" : $(back) ] ; | |
395 | compile_flags = [ MATCH "(.*)-v" : $(compile_flags) ] ; | |
396 | link_flags = [ SHELL "$(command) -v -xtarget=native64 2>/dev/null" ] ; | |
397 | link_flags = [ MATCH "--------------------(.*)" : $(link_flags) ] ; | |
398 | link_flags = [ MATCH "(.*)--------------------" : $(link_flags) ] ; | |
399 | ||
400 | # strip out -v from compile options | |
401 | local front = [ MATCH "(.*)-v" : $(link_flags) ] ; | |
402 | local back = [ MATCH "-v(.*)" : $(link_flags) ] ; | |
403 | link_flags = "$(front) $(back)" ; | |
404 | front = [ MATCH "(.*)-xtarget=native64" : $(link_flags) ] ; | |
405 | back = [ MATCH "-xtarget=native64(.*)" : $(link_flags) ] ; | |
406 | link_flags = "$(front) $(back)" ; | |
407 | } | |
408 | else | |
409 | { | |
410 | # Ibm POE | |
411 | if $(.debug-configuration) | |
412 | { | |
413 | ECHO "Found IBM MPI wrapper compiler: $(command)" ; | |
414 | } | |
415 | ||
416 | # | |
417 | compile_flags = [ SHELL "$(command) -c -v 2>/dev/null" ] ; | |
418 | compile_flags = [ MATCH "(.*)exec: export.*" : $(compile_flags) ] ; | |
419 | local front = [ MATCH "(.*)-v" : $(compile_flags) ] ; | |
420 | local back = [ MATCH "-v(.*)" : $(compile_flags) ] ; | |
421 | compile_flags = "$(front) $(back)" ; | |
422 | front = [ MATCH "(.*)-c" : $(compile_flags) ] ; | |
423 | back = [ MATCH "-c(.*)" : $(compile_flags) ] ; | |
424 | compile_flags = "$(front) $(back)" ; | |
425 | link_flags = $(compile_flags) ; | |
426 | ||
427 | # get location of mpif.h from mpxlf | |
428 | local f_flags = [ SHELL "mpxlf -v 2>/dev/null" ] ; | |
429 | f_flags = [ MATCH "(.*)exec: export.*" : $(f_flags) ] ; | |
430 | front = [ MATCH "(.*)-v" : $(f_flags) ] ; | |
431 | back = [ MATCH "-v(.*)" : $(f_flags) ] ; | |
432 | f_flags = "$(front) $(back)" ; | |
433 | f_flags = [ MATCH "xlf_r(.*)" : $(f_flags) ] ; | |
434 | f_flags = [ MATCH "-F:mpxlf_r(.*)" : $(f_flags) ] ; | |
435 | compile_flags = [ strip-eol $(compile_flags) ] ; | |
436 | compile_flags = "$(compile_flags) $(f_flags)" ; | |
437 | } | |
438 | } | |
439 | # Cray | |
440 | else if [ safe-shell-command "$(command) -v" ] | |
441 | { | |
442 | compile_flags = [ safe-shell-command "$(command) -###" ] ; | |
443 | link_flags = [ safe-shell-command "$(command) -###" ] ; | |
444 | # ECHO "Noel: compile_flags: $(compile_flags)" ; | |
445 | # ECHO "Noel: link_flags: $(link_flags)" ; | |
446 | result = " " ; | |
447 | } | |
448 | ||
449 | # Prepend COMPILER as the executable name, to match the format of | |
450 | ||
451 | if $(result) || $(compile_flags) && $(link_flags) | |
452 | { | |
453 | if $(result) | |
454 | { | |
455 | result = [ strip-eol $(result) ] ; | |
456 | options = [ cmdline_to_features $(result) ] ; | |
457 | } | |
458 | else | |
459 | { | |
460 | compile_flags = [ strip-eol $(compile_flags) ] ; | |
461 | link_flags = [ strip-eol $(link_flags) ] ; | |
462 | ||
463 | # Separately process compilation and link features, then combine | |
464 | # them at the end. | |
465 | local compile_features = [ cmdline_to_features $(compile_flags) | |
466 | : "<cxxflags>" ] ; | |
467 | local link_features = [ cmdline_to_features $(link_flags) | |
468 | : "<linkflags>" ] ; | |
469 | options = $(compile_features) $(link_features) ; | |
470 | } | |
471 | ||
472 | # If requested, display MPI configuration information. | |
473 | if $(.debug-configuration) | |
474 | { | |
475 | if $(result) | |
476 | { | |
477 | ECHO " Wrapper compiler command line: $(result)" ; | |
478 | } | |
479 | else | |
480 | { | |
481 | local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" | |
482 | : $(compile_flags) ] ; | |
483 | ECHO "MPI compilation flags: $(match[2])" ; | |
484 | local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" | |
485 | : $(link_flags) ] ; | |
486 | ECHO "MPI link flags: $(match[2])" ; | |
487 | } | |
488 | } | |
489 | } | |
490 | else | |
491 | { | |
492 | if $(command) | |
493 | { | |
494 | ECHO "MPI auto-detection failed: unknown wrapper compiler $(command)" ; | |
495 | ECHO "Please report this error to the Boost mailing list: http://www.boost.org" ; | |
496 | } | |
497 | else if $(mpicxx) | |
498 | { | |
499 | ECHO "MPI auto-detection failed: unable to find wrapper compiler $(mpicxx)" ; | |
500 | } | |
501 | else | |
502 | { | |
503 | ECHO "MPI auto-detection failed: unable to find wrapper compiler `mpic++' or `mpiCC'" ; | |
504 | } | |
505 | ECHO "You will need to manually configure MPI support." ; | |
506 | } | |
507 | ||
508 | } | |
509 | ||
510 | # Find mpirun (or its equivalent) and its flags | |
511 | if ! $(.mpirun) | |
512 | { | |
513 | .mpirun = | |
514 | [ common.get-invocation-command mpi : mpirun : $(mpirun-with-options[1]) ] ; | |
515 | .mpirun_flags = $(mpirun-with-options[2-]) ; | |
516 | .mpirun_flags ?= -np ; | |
517 | } | |
518 | ||
519 | if $(.debug-configuration) | |
520 | { | |
521 | if $(options) | |
522 | { | |
523 | echo "MPI build features: " ; | |
524 | ECHO $(options) ; | |
525 | } | |
526 | ||
527 | if $(.mpirun) | |
528 | { | |
529 | echo "MPI launcher: $(.mpirun) $(.mpirun_flags)" ; | |
530 | } | |
531 | ||
532 | ECHO "====================================================" ; | |
533 | } | |
534 | ||
535 | if $(options) | |
536 | { | |
537 | .configured = true ; | |
538 | ||
539 | # Set up the "mpi" alias | |
540 | alias mpi : : : : $(options) ; | |
541 | } | |
542 | } | |
543 | ||
544 | # States whether MPI has bee configured | |
545 | rule configured ( ) | |
546 | { | |
547 | return $(.configured) ; | |
548 | } | |
549 | ||
92f5a8d4 | 550 | # Returns the "extra" requirements needed to build MPI. These requirements are |
7c673cae FG |
551 | # part of the /mpi//mpi library target, but they need to be added to anything |
552 | # that uses MPI directly to work around bugs in BBv2's propagation of | |
553 | # requirements. | |
554 | rule extra-requirements ( ) | |
555 | { | |
556 | return $(MPI_EXTRA_REQUIREMENTS) ; | |
557 | } | |
558 | ||
559 | # Support for testing; borrowed from Python | |
560 | type.register RUN_MPI_OUTPUT ; | |
561 | type.register RUN_MPI : : TEST ; | |
562 | ||
563 | class mpi-test-generator : generator | |
564 | { | |
565 | import property-set ; | |
566 | ||
567 | rule __init__ ( * : * ) | |
568 | { | |
569 | generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; | |
570 | self.composing = true ; | |
571 | } | |
572 | ||
573 | rule run ( project name ? : property-set : sources * : multiple ? ) | |
574 | { | |
575 | # Generate an executable from the sources. This is the executable we will run. | |
576 | local executable = | |
577 | [ generators.construct $(project) $(name) : EXE : $(property-set) : $(sources) ] ; | |
578 | ||
579 | result = | |
580 | [ construct-result $(executable[2-]) : $(project) $(name)-run : $(property-set) ] ; | |
581 | } | |
582 | } | |
583 | ||
584 | # Use mpi-test-generator to generate MPI tests from sources | |
585 | generators.register | |
586 | [ new mpi-test-generator mpi.capture-output : : RUN_MPI_OUTPUT ] ; | |
587 | ||
588 | generators.register-standard testing.expect-success | |
589 | : RUN_MPI_OUTPUT : RUN_MPI ; | |
590 | ||
591 | # The number of processes to spawn when executing an MPI test. | |
11fdf7f2 | 592 | feature "mpi:processes" : : free incidental ; |
7c673cae FG |
593 | |
594 | # The flag settings on testing.capture-output do not | |
595 | # apply to mpi.capture output at the moment. | |
596 | # Redo this explicitly. | |
597 | toolset.flags mpi.capture-output ARGS <testing.arg> ; | |
11fdf7f2 TL |
598 | toolset.uses-features mpi.capture-output : |
599 | <testing.launcher> <testing.execute> <dll-path> <xdll-path> <target-os> | |
600 | <mpi:processes> ; | |
601 | ||
7c673cae FG |
602 | rule capture-output ( target : sources * : properties * ) |
603 | { | |
604 | # Use the standard capture-output rule to run the tests | |
605 | testing.capture-output $(target) : $(sources[1]) : $(properties) ; | |
606 | ||
607 | # Determine the number of processes we should run on. | |
608 | local num_processes = [ property.select <mpi:processes> : $(properties) ] ; | |
609 | num_processes = $(num_processes:G=) ; | |
610 | ||
611 | # serialize the MPI tests to avoid overloading systems | |
612 | JAM_SEMAPHORE on $(target) = <s>mpi-run-semaphore ; | |
613 | ||
614 | # We launch MPI processes using the "mpirun" equivalent specified by the user. | |
615 | LAUNCHER on $(target) = | |
616 | [ on $(target) return $(.mpirun) $(.mpirun_flags) $(num_processes) ] ; | |
617 | } | |
618 | ||
619 | # Creates a set of test cases to be run through the MPI launcher. The name, sources, | |
620 | # and requirements are the same as for any other test generator. However, schedule is | |
621 | # a list of numbers, which indicates how many processes each test run will use. For | |
622 | # example, passing 1 2 7 will run the test with 1 process, then 2 processes, then 7 | |
623 | # 7 processes. The name provided is just the base name: the actual tests will be | |
92f5a8d4 | 624 | # the name followed by a hyphen, then the number of processes. |
7c673cae FG |
625 | rule mpi-test ( name : sources * : requirements * : schedule * ) |
626 | { | |
627 | sources ?= $(name).cpp ; | |
628 | schedule ?= 1 2 3 4 7 8 13 17 ; | |
629 | ||
630 | local result ; | |
631 | for processes in $(schedule) | |
632 | { | |
633 | result += [ testing.make-test | |
634 | run-mpi : $(sources) /boost/mpi//boost_mpi | |
635 | : $(requirements) <toolset>msvc:<link>static <mpi:processes>$(processes) : $(name)-$(processes) ] ; | |
636 | } | |
637 | return $(result) ; | |
638 | } |