]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/src/tools/mpi.jam
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / build / src / tools / mpi.jam
CommitLineData
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
57import "class" : new ;
58import common ;
59import feature : feature ;
60import generators ;
61import os ;
62import project ;
63import property ;
64import testing ;
65import toolset ;
66import type ;
67import path ;
68
69# Make this module a project
70project.initialize $(__name__) ;
71project mpi ;
72
73if [ 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
85rule 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.
105rule 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.
130rule 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.
232local 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.
239rule 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
545rule 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.
554rule extra-requirements ( )
555{
556 return $(MPI_EXTRA_REQUIREMENTS) ;
557}
558
559# Support for testing; borrowed from Python
560type.register RUN_MPI_OUTPUT ;
561type.register RUN_MPI : : TEST ;
562
563class 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
585generators.register
586 [ new mpi-test-generator mpi.capture-output : : RUN_MPI_OUTPUT ] ;
587
588generators.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 592feature "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.
597toolset.flags mpi.capture-output ARGS <testing.arg> ;
11fdf7f2
TL
598toolset.uses-features mpi.capture-output :
599 <testing.launcher> <testing.execute> <dll-path> <xdll-path> <target-os>
600 <mpi:processes> ;
601
7c673cae
FG
602rule 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
625rule 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}