blob: fac00d1b74b2658a170d79d24a67fcb964840cde [file] [log] [blame]
A. Unique TensorFlower73ea2872017-07-25 13:30:03 -07001# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""configure script to get build parameters from user."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import errno
22import os
23import platform
24import re
25import site
26import subprocess
27import sys
28
29_TF_BAZELRC = '.tf_configure.bazelrc'
30_DEFAULT_CUDA_VERSION = '8.0'
31_DEFAULT_CUDNN_VERSION = '6'
32_DEFAULT_CUDA_COMPUTE_CAPABILITIES = '3.5,5.2'
33_DEFAULT_CUDA_PATH = '/usr/local/cuda'
34_DEFAULT_CUDA_PATH_LINUX = '/opt/cuda'
35_DEFAULT_CUDA_PATH_WIN = ('C:/Program Files/NVIDIA GPU Computing '
36 'Toolkit/CUDA/v%s' % _DEFAULT_CUDA_VERSION)
37_TF_OPENCL_VERSION = '1.2'
38_DEFAULT_COMPUTECPP_TOOLKIT_PATH = '/usr/local/computecpp'
39
40
41def is_windows():
42 return platform.system() == 'Windows'
43
44
45def is_linux():
46 return platform.system() == 'Linux'
47
48
49def is_macos():
50 return platform.system() == 'Darwin'
51
52
53def is_ppc64le():
54 return platform.machine() == 'ppc64le'
55
56
57def get_input(question):
58 try:
59 try:
60 answer = raw_input(question)
61 except NameError:
62 answer = input(question) # pylint: disable=bad-builtin
63 except EOFError:
64 answer = ''
65 return answer
66
67
68def symlink_force(target, link_name):
69 """Force symlink, equivalent of 'ln -sf'.
70
71 Args:
72 target: items to link to.
73 link_name: name of the link.
74 """
75 try:
76 os.symlink(target, link_name)
77 except OSError as e:
78 if e.errno == errno.EEXIST:
79 os.remove(link_name)
80 os.symlink(target, link_name)
81 else:
82 raise e
83
84
85def sed_in_place(filename, old, new):
86 """Replace old string with new string in file.
87
88 Args:
89 filename: string for filename.
90 old: string to replace.
91 new: new string to replace to.
92 """
93 with open(filename, 'r') as f:
94 filedata = f.read()
95 newdata = filedata.replace(old, new)
96 with open(filename, 'w') as f:
97 f.write(newdata)
98
99
100def remove_line_with(filename, token):
101 """Remove lines that contain token from file.
102
103 Args:
104 filename: string for filename.
105 token: string token to check if to remove a line from file or not.
106 """
107 with open(filename, 'r') as f:
108 filedata = f.read()
109
110 with open(filename, 'w') as f:
111 for line in filedata.strip().split('\n'):
112 if token not in line:
113 f.write(line + '\n')
114
115
116def write_to_bazelrc(line):
117 with open(_TF_BAZELRC, 'a') as f:
118 f.write(line + '\n')
119
120
121def write_action_env_to_bazelrc(var_name, var):
122 write_to_bazelrc('build --action_env %s="%s"' % (var_name, str(var)))
123
124
125def run_shell(cmd):
126 return subprocess.check_output(cmd, shell=True).decode('UTF-8').strip()
127
128
129def cygpath(path):
130 """Convert path from posix to windows."""
131 return run_shell('cygpath -m "%s"' % path)
132
133
134def get_python_path(environ_cp):
135 """Get the python site package paths."""
136 python_paths = []
137 if environ_cp.get('PYTHONPATH'):
138 python_paths = environ_cp.get('PYTHONPATH').split(':')
139 try:
140 library_paths = site.getsitepackages()
141 except AttributeError:
142 from distutils.sysconfig import get_python_lib # pylint: disable=g-import-not-at-top
143 library_paths = [get_python_lib()]
144 all_paths = set(python_paths + library_paths)
145
146 paths = []
147 for path in all_paths:
148 if os.path.isdir(path):
149 paths.append(path)
150 return paths
151
152
153def setup_python(environ_cp):
154 """Setup python related env variables."""
155 # Get PYTHON_BIN_PATH, default is the current running python.
156 default_python_bin_path = sys.executable
157 ask_python_bin_path = ('Please specify the location of python. [Default is '
158 '%s]: ') % default_python_bin_path
159 while True:
160 python_bin_path = get_from_env_or_user_or_default(
161 environ_cp, 'PYTHON_BIN_PATH', ask_python_bin_path,
162 default_python_bin_path)
163 # Check if the path is valid
164 if (os.path.isfile(python_bin_path) and os.access(
165 python_bin_path, os.X_OK)) or (os.path.isdir(python_bin_path)):
166 break
167 elif not os.path.exists(python_bin_path):
168 print('Invalid python path: %s cannot be found.' % python_bin_path)
169 else:
170 print('%s is not executable. Is it the python binary?' % python_bin_path)
171 environ_cp['PYTHON_BIN_PATH'] = ''
172
173 # Get PYTHON_LIB_PATH
174 python_lib_path = environ_cp.get('PYTHON_LIB_PATH')
175 if not python_lib_path:
176 python_lib_paths = get_python_path(environ_cp)
177 if environ_cp.get('USE_DEFAULT_PYTHON_LIB_PATH') == '1':
178 environ_cp['PYTHON_LIB_PATH'] = python_lib_paths[0]
179 else:
180 print('Found possible Python library paths:\n%s' %
181 '\n'.join(python_lib_paths))
182 default_python_lib_path = python_lib_paths[0]
183 python_lib_path = get_input(
184 'Please input the desired Python library path to use. Default is %s'
185 % python_lib_paths[0])
186 if not python_lib_path:
187 python_lib_path = default_python_lib_path
188 environ_cp['PYTHON_LIB_PATH'] = python_lib_path
189
190 python_major_version = sys.version_info[0]
191 # Convert python path to Windows style before writing into bazel.rc
192 if is_windows():
193 python_bin_path = cygpath(python_bin_path)
194 python_lib_path = cygpath(python_lib_path)
195
196 # Set-up env variables used by python_configure.bzl
197 write_action_env_to_bazelrc('PYTHON_BIN_PATH', python_bin_path)
198 write_action_env_to_bazelrc('PYTHON_LIB_PATH', python_lib_path)
199 write_to_bazelrc('build --define PYTHON_BIN_PATH="%s"' % python_bin_path)
200 write_to_bazelrc('build --define PYTHON_LIB_PATH="%s"' % python_lib_path)
201 write_to_bazelrc('build --force_python=py%s' % python_major_version)
202 write_to_bazelrc('build --host_force_python=py%s' % python_major_version)
203 write_to_bazelrc('build --python%s_path=\"%s"' % (python_major_version,
204 python_bin_path))
205 write_to_bazelrc('test --force_python=py%s' % python_major_version)
206 write_to_bazelrc('test --host_force_python=py%s' % python_major_version)
207 write_to_bazelrc('test --define PYTHON_BIN_PATH="%s"' % python_bin_path)
208 write_to_bazelrc('test --define PYTHON_LIB_PATH="%s"' % python_lib_path)
209 write_to_bazelrc('run --define PYTHON_BIN_PATH="%s"' % python_bin_path)
210 write_to_bazelrc('run --define PYTHON_LIB_PATH="%s"' % python_lib_path)
211 environ_cp['PYTHON_BIN_PATH'] = python_bin_path
212
213 # Write tools/python_bin_path.sh
214 with open('tools/python_bin_path.sh', 'w') as f:
215 f.write('export PYTHON_BIN_PATH="%s"' % python_bin_path)
216
217
218def reset_tf_configure_bazelrc():
219 """Reset file that contains customized config settings."""
220 open(_TF_BAZELRC, 'w').close()
221
222 home = os.path.expanduser('~')
223 if not os.path.exists('.bazelrc'):
224 if os.path.exists(os.path.join(home, '.bazelrc')):
225 with open('.bazelrc', 'a') as f:
226 f.write('import %s/.bazelrc\n' % home)
227 else:
228 open('.bazelrc', 'w').close()
229
230 remove_line_with('.bazelrc', 'tf_configure')
231 with open('.bazelrc', 'a') as f:
232 f.write('import %workspace%/.tf_configure.bazelrc\n')
233
234
235def run_gen_git_source(environ_cp):
236 """Run the gen_git_source to create links.
237
238 The links are for bazel to track dependencies for git hash propagation.
239
240 Args:
241 environ_cp: copy of the os.environ.
242 """
243 cmd = '%s tensorflow/tools/git/gen_git_source.py --configure %s' % (
244 environ_cp.get('PYTHON_BIN_PATH'), os.getcwd())
245 os.system(cmd)
246
247
248def cleanup_makefile():
249 """Delete any leftover BUILD files from the Makefile build.
250
251 These files could interfere with Bazel parsing.
252 """
253 makefile_download_dir = 'tensorflow/contrib/makefile/downloads'
254 if os.path.isdir(makefile_download_dir):
255 for root, _, filenames in os.walk(makefile_download_dir):
256 for f in filenames:
257 if f.endswith('BUILD'):
258 os.remove(os.path.join(root, f))
259
260
261def get_var(environ_cp,
262 var_name,
263 query_item,
264 enabled_by_default,
265 question=None,
266 yes_reply=None,
267 no_reply=None):
268 """Get boolean input from user.
269
270 If var_name is not set in env, ask user to enable query_item or not. If the
271 response is empty, use the default.
272
273 Args:
274 environ_cp: copy of the os.environ.
275 var_name: string for name of environment variable, e.g. "TF_NEED_HDFS".
276 query_item: string for feature related to the variable, e.g. "Hadoop File
277 System".
278 enabled_by_default: boolean for default behavior.
279 question: optional string for how to ask for user input.
280 yes_reply: optionanl string for reply when feature is enabled.
281 no_reply: optional string for reply when feature is disabled.
282
283 Returns:
284 boolean value of the variable.
285 """
286 if not question:
287 question = 'Do you wish to build TensorFlow with %s support?' % query_item
288 if not yes_reply:
289 yes_reply = '%s support will be enabled for TensorFlow.' % query_item
290 if not no_reply:
291 no_reply = 'No %s' % yes_reply
292
293 yes_reply += '\n'
294 no_reply += '\n'
295
296 if enabled_by_default:
297 question += ' [Y/n]: '
298 else:
299 question += ' [y/N]: '
300
301 var = environ_cp.get(var_name)
302 while var is None:
303 user_input_origin = get_input(question)
304 user_input = user_input_origin.strip().lower()
305 if user_input == 'y':
306 print(yes_reply)
307 var = True
308 elif user_input == 'n':
309 print(no_reply)
310 var = False
311 elif not user_input:
312 if enabled_by_default:
313 print(yes_reply)
314 var = True
315 else:
316 print(no_reply)
317 var = False
318 else:
319 print('Invalid selection: %s' % user_input_origin)
320 return var
321
322
323def set_build_var(environ_cp, var_name, query_item, option_name,
324 enabled_by_default):
325 """Set if query_item will be enabled for the build.
326
327 Ask user if query_item will be enabled. Default is used if no input is given.
328 Set subprocess environment variable and write to .bazelrc if enabled.
329
330 Args:
331 environ_cp: copy of the os.environ.
332 var_name: string for name of environment variable, e.g. "TF_NEED_HDFS".
333 query_item: string for feature related to the variable, e.g. "Hadoop File
334 System".
335 option_name: string for option to define in .bazelrc.
336 enabled_by_default: boolean for default behavior.
337 """
338
339 var = str(int(get_var(environ_cp, var_name, query_item, enabled_by_default)))
340 environ_cp[var_name] = var
341 if var == '1':
342 write_to_bazelrc('build --define %s=true' % option_name)
343
344
345def set_action_env_var(environ_cp,
346 var_name,
347 query_item,
348 enabled_by_default,
349 question=None,
350 yes_reply=None,
351 no_reply=None):
352 """Set boolean action_env variable.
353
354 Ask user if query_item will be enabled. Default is used if no input is given.
355 Set environment variable and write to .bazelrc.
356
357 Args:
358 environ_cp: copy of the os.environ.
359 var_name: string for name of environment variable, e.g. "TF_NEED_HDFS".
360 query_item: string for feature related to the variable, e.g. "Hadoop File
361 System".
362 enabled_by_default: boolean for default behavior.
363 question: optional string for how to ask for user input.
364 yes_reply: optionanl string for reply when feature is enabled.
365 no_reply: optional string for reply when feature is disabled.
366 """
367 var = int(
368 get_var(environ_cp, var_name, query_item, enabled_by_default, question,
369 yes_reply, no_reply))
370
371 write_action_env_to_bazelrc(var_name, var)
372 environ_cp[var_name] = str(var)
373
374
375def check_bazel_version(min_version):
376 """Check installed bezel version is at least min_version.
377
378 Args:
379 min_version: string for minimum bazel version.
380 """
381 try:
382 curr_version = run_shell('bazel version')
383 except subprocess.CalledProcessError:
384 print('Cannot find bazel. Please install bazel.')
385 sys.exit(0)
386
387 for line in curr_version.split('\n'):
388 if 'Build label: ' in line:
389 curr_version = line.split('Build label: ')[1]
390 break
391
392 min_version_segments = min_version.split('.')
393 curr_version_segments = curr_version.split('.')
394
395 # Check if current bazel version can be detected properly.
396 for seg in curr_version_segments:
397 if not seg.isdigit():
398 print('WARNING: current bazel installation is not a release version.')
399 print('Make sure you are running at least bazel %s' % min_version)
400 return
401
402 min_version_str = ''.join(['%03d' % int(seg) for seg in min_version_segments])
403 curr_version_str = ''.join(
404 ['%03d' % int(seg) for seg in curr_version_segments])
405 if int(curr_version_str) < int(min_version_str):
406 print('Please upgrade your bazel installation to version %s or higher to '
407 'build TensorFlow!' % min_version)
408 sys.exit(0)
409
410
411def set_cc_opt_flags(environ_cp):
412 """Set up architecture-dependent optimization flags.
413
414 Also append CC optimization flags to bazel.rc..
415
416 Args:
417 environ_cp: copy of the os.environ.
418 """
419 if is_ppc64le():
420 # gcc on ppc64le does not support -march, use mcpu instead
421 default_cc_opt_flags = '-mcpu=native'
422 else:
423 default_cc_opt_flags = '-march=native'
424 question = ('Please specify optimization flags to use during compilation when'
425 ' bazel option "--config=opt" is specified [Default is %s]: '
426 ) % default_cc_opt_flags
427 cc_opt_flags = get_from_env_or_user_or_default(environ_cp, 'CC_OPT_FLAGS',
428 question, default_cc_opt_flags)
429 for opt in cc_opt_flags.split():
430 write_to_bazelrc('build:opt --cxxopt=%s --copt=%s' % (opt, opt))
431
432
433def set_tf_cuda_clang(environ_cp):
434 """set TF_CUDA_CLANG action_env.
435
436 Args:
437 environ_cp: copy of the os.environ.
438 """
439 question = 'Do you want to use clang as CUDA compiler?'
440 yes_reply = 'Clang will be used as CUDA compiler.'
441 no_reply = 'nvcc will be used as CUDA compiler.'
442 set_action_env_var(
443 environ_cp,
444 'TF_CUDA_CLANG',
445 None,
446 False,
447 question=question,
448 yes_reply=yes_reply,
449 no_reply=no_reply)
450
451
452def get_from_env_or_user_or_default(environ_cp, var_name, ask_for_var,
453 var_default):
454 """Get var_name either from env, or user or default.
455
456 If var_name has been set as environment variable, use the preset value, else
457 ask for user input. If no input is provided, the default is used.
458
459 Args:
460 environ_cp: copy of the os.environ.
461 var_name: string for name of environment variable, e.g. "TF_NEED_HDFS".
462 ask_for_var: string for how to ask for user input.
463 var_default: default value string.
464
465 Returns:
466 string value for var_name
467 """
468 var = environ_cp.get(var_name)
469 if not var:
470 var = get_input(ask_for_var)
471 if not var:
472 var = var_default
473 return var
474
475
476def set_clang_cuda_compiler_path(environ_cp):
477 """Set CLANG_CUDA_COMPILER_PATH."""
478 default_clang_path = run_shell('which clang || true')
479 ask_clang_path = ('Please specify which clang should be used as device and '
480 'host compiler. [Default is %s]: ') % default_clang_path
481
482 while True:
483 clang_cuda_compiler_path = get_from_env_or_user_or_default(
484 environ_cp, 'CLANG_CUDA_COMPILER_PATH', ask_clang_path,
485 default_clang_path)
486 if os.path.exists(clang_cuda_compiler_path):
487 break
488
489 # Reset and retry
490 print('Invalid clang path: %s cannot be found.' % clang_cuda_compiler_path)
491 environ_cp['CLANG_CUDA_COMPILER_PATH'] = ''
492
493 # Set CLANG_CUDA_COMPILER_PATH
494 environ_cp['CLANG_CUDA_COMPILER_PATH'] = clang_cuda_compiler_path
495 write_action_env_to_bazelrc('CLANG_CUDA_COMPILER_PATH',
496 clang_cuda_compiler_path)
497
498
499def set_gcc_host_compiler_path(environ_cp):
500 """Set GCC_HOST_COMPILER_PATH."""
501 default_gcc_host_compiler_path = run_shell('which gcc || true')
502 cuda_bin_symlink = '%s/bin/gcc' % environ_cp.get('CUDA_TOOLKIT_PATH')
503
504 if os.path.islink(cuda_bin_symlink):
505 # os.readlink is only available in linux
506 default_gcc_host_compiler_path = run_shell('readlink %s' % cuda_bin_symlink)
507
508 ask_gcc_path = (
509 'Please specify which gcc should be used by nvcc as the '
510 'host compiler. [Default is %s]: ') % default_gcc_host_compiler_path
511 while True:
512 gcc_host_compiler_path = get_from_env_or_user_or_default(
513 environ_cp, 'GCC_HOST_COMPILER_PATH', ask_gcc_path,
514 default_gcc_host_compiler_path)
515
516 if os.path.exists(gcc_host_compiler_path):
517 break
518
519 # Reset and retry
520 print('Invalid gcc path. %s cannot be found' % gcc_host_compiler_path)
521 environ_cp['GCC_HOST_COMPILER_PATH'] = ''
522
523 # Set GCC_HOST_COMPILER_PATH
524 environ_cp['GCC_HOST_COMPILER_PATH'] = gcc_host_compiler_path
525 write_action_env_to_bazelrc('GCC_HOST_COMPILER_PATH', gcc_host_compiler_path)
526
527
528def set_tf_cuda_version(environ_cp):
529 """Set CUDA_TOOLKIT_PATH and TF_CUDA_VERSION."""
530 ask_cuda_version = (
531 'Please specify the CUDA SDK version you want to use, '
532 'e.g. 7.0. [Leave empty to default to CUDA %s]: ') % _DEFAULT_CUDA_VERSION
533
534 while True:
535 # Configure the Cuda SDK version to use.
536 tf_cuda_version = get_from_env_or_user_or_default(
537 environ_cp, 'TF_CUDA_VERSION', ask_cuda_version, _DEFAULT_CUDA_VERSION)
538
539 # Find out where the CUDA toolkit is installed
540 default_cuda_path = _DEFAULT_CUDA_PATH
541 if is_windows():
542 default_cuda_path = cygpath(
543 environ_cp.get('CUDA_PATH', _DEFAULT_CUDA_PATH_WIN))
544 elif is_linux():
545 # If the default doesn't exist, try an alternative default.
546 if (not os.path.exists(default_cuda_path)
547 ) and os.path.exists(_DEFAULT_CUDA_PATH_LINUX):
548 default_cuda_path = _DEFAULT_CUDA_PATH_LINUX
549 ask_cuda_path = ('Please specify the location where CUDA %s toolkit is'
550 ' installed. Refer to README.md for more details. '
551 '[Default is %s]: ') % (tf_cuda_version, default_cuda_path)
552 cuda_toolkit_path = get_from_env_or_user_or_default(
553 environ_cp, 'CUDA_TOOLKIT_PATH', ask_cuda_path, default_cuda_path)
554
555 if is_windows():
556 cuda_rt_lib_path = 'lib/x64/cudart.lib'
557 elif is_linux():
558 cuda_rt_lib_path = 'lib64/libcudart.so.%s' % tf_cuda_version
559 elif is_macos():
560 cuda_rt_lib_path = 'lib/libcudart.%s.dylib' % tf_cuda_version
561
562 cuda_toolkit_path_full = os.path.join(cuda_toolkit_path, cuda_rt_lib_path)
563 if os.path.exists(cuda_toolkit_path_full):
564 break
565
566 # Reset and retry
567 print('Invalid path to CUDA %s toolkit. %s cannot be found' %
568 (tf_cuda_version, cuda_toolkit_path_full))
569 environ_cp['TF_CUDA_VERSION'] = ''
570 environ_cp['CUDA_TOOLKIT_PATH'] = ''
571
572 # Set CUDA_TOOLKIT_PATH and TF_CUDA_VERSION
573 environ_cp['CUDA_TOOLKIT_PATH'] = cuda_toolkit_path
574 write_action_env_to_bazelrc('CUDA_TOOLKIT_PATH', cuda_toolkit_path)
575 environ_cp['TF_CUDA_VERSION'] = tf_cuda_version
576 write_action_env_to_bazelrc('TF_CUDA_VERSION', tf_cuda_version)
577
578
579def set_tf_cunn_version(environ_cp):
580 """Set CUDNN_INSTALL_PATH and TF_CUDNN_VERSION."""
581 ask_cudnn_version = (
582 '"Please specify the cuDNN version you want to use. '
583 '[Leave empty to default to cuDNN %s.0]: ') % _DEFAULT_CUDNN_VERSION
584
585 while True:
586 tf_cudnn_version = get_from_env_or_user_or_default(
587 environ_cp, 'TF_CUDNN_VERSION', ask_cudnn_version,
588 _DEFAULT_CUDNN_VERSION)
589
590 default_cudnn_path = environ_cp.get('CUDA_TOOLKIT_PATH')
591 ask_cudnn_path = (r'Please specify the location where cuDNN %s library is '
592 'installed. Refer to README.md for more details. [Default'
593 ' is %s]:') % (tf_cudnn_version, default_cudnn_path)
594 cudnn_install_path = get_from_env_or_user_or_default(
595 environ_cp, 'CUDNN_INSTALL_PATH', ask_cudnn_path, default_cudnn_path)
596
597 # Result returned from "read" will be used unexpanded. That make "~"
598 # unusable. Going through one more level of expansion to handle that.
599 cudnn_install_path = os.path.realpath(
600 os.path.expanduser(cudnn_install_path))
601 if is_windows():
602 cudnn_install_path = cygpath(cudnn_install_path)
603
604 if is_windows():
605 cuda_dnn_lib_path = 'lib/x64/cudnn.lib'
606 cuda_dnn_lib_alt_path = 'lib/x64/cudnn.lib'
607 elif is_linux():
608 cuda_dnn_lib_path = 'lib64/libcudnn.so.%s' % tf_cudnn_version
609 cuda_dnn_lib_alt_path = 'libcudnn.so.%s' % tf_cudnn_version
610 elif is_macos():
611 cuda_dnn_lib_path = 'lib/libcudnn.%s.dylib' % tf_cudnn_version
612 cuda_dnn_lib_alt_path = 'libcudnn.%s.dylib' % tf_cudnn_version
613
614 cuda_dnn_lib_path_full = os.path.join(cudnn_install_path, cuda_dnn_lib_path)
615 cuda_dnn_lib_alt_path_full = os.path.join(cudnn_install_path,
616 cuda_dnn_lib_alt_path)
617 if os.path.exists(cuda_dnn_lib_path_full) or os.path.exists(
618 cuda_dnn_lib_alt_path_full):
619 break
620
621 # Try another alternative for Linux
622 if is_linux():
623 if subprocess.call(['which', 'ldconfig']):
624 ldconfig_bin = '/sbin/ldconfig'
625 else:
626 ldconfig_bin = 'ldconfig'
627 cudnn_path_from_ldconfig = run_shell(
628 r'%s -p | sed -n "s/.*libcudnn.so .* => \(.*\)/\\1/p"' % ldconfig_bin)
629 if os.path.exists('%s.%s' % (cudnn_path_from_ldconfig, tf_cudnn_version)):
630 cudnn_install_path = os.path.dirname(cudnn_path_from_ldconfig)
631 break
632
633 # Reset and Retry
634 print(
635 'Invalid path to cuDNN %s toolkit. None of the following files can be '
636 'found:' % tf_cudnn_version)
637 print(cuda_dnn_lib_path_full)
638 print(cuda_dnn_lib_alt_path_full)
639 if is_linux():
640 print('%s.%s' % (cudnn_path_from_ldconfig, tf_cudnn_version))
641
642 environ_cp['TF_CUDNN_VERSION'] = ''
643
644 # Set CUDNN_INSTALL_PATH and TF_CUDNN_VERSION
645 environ_cp['CUDNN_INSTALL_PATH'] = cudnn_install_path
646 write_action_env_to_bazelrc('CUDNN_INSTALL_PATH', cudnn_install_path)
647 environ_cp['TF_CUDNN_VERSION'] = tf_cudnn_version
648 write_action_env_to_bazelrc('TF_CUDNN_VERSION', tf_cudnn_version)
649
650
651def get_native_cuda_compute_capabilities(environ_cp):
652 """Get native cuda compute capabilities.
653
654 Args:
655 environ_cp: copy of the os.environ.
656 Returns:
657 string of native cuda compute capabilities, separated by comma.
658 """
659 device_query_bin = os.path.join(
660 environ_cp.get('CUDA_TOOLKIT_PATH'), 'extras/demo_suite/deviceQuery')
661 cmd = (r'"%s" | grep "Capability" | grep -o "[0-9]*\.[0-9]*" | sed '
662 '":a;{N;s/\\n/,/};ba"') % device_query_bin
663 try:
664 output = run_shell(cmd)
665 except subprocess.CalledProcessError:
666 output = ''
667 return output
668
669
670def set_tf_cuda_compute_capabilities(environ_cp):
671 """Set TF_CUDA_COMPUTE_CAPABILITIES."""
672 while True:
673 native_cuda_compute_capabilities = get_native_cuda_compute_capabilities(
674 environ_cp)
675 if not native_cuda_compute_capabilities:
676 default_cuda_compute_capabilities = _DEFAULT_CUDA_COMPUTE_CAPABILITIES
677 else:
678 default_cuda_compute_capabilities = native_cuda_compute_capabilities
679
680 ask_cuda_compute_capabilities = (
681 'Please specify a list of comma-separated '
682 'Cuda compute capabilities you want to '
683 'build with.\nYou can find the compute '
684 'capability of your device at: '
685 'https://developer.nvidia.com/cuda-gpus.\nPlease'
686 ' note that each additional compute '
687 'capability significantly increases your '
688 'build time and binary size. [Default is: %s]' %
689 default_cuda_compute_capabilities)
690 tf_cuda_compute_capabilities = get_from_env_or_user_or_default(
691 environ_cp, 'TF_CUDA_COMPUTE_CAPABILITIES',
692 ask_cuda_compute_capabilities, default_cuda_compute_capabilities)
693 # Check whether all capabilities from the input is valid
694 all_valid = True
695 for compute_capability in tf_cuda_compute_capabilities.split(','):
696 if not re.match('[0-9]+.[0-9]+', compute_capability):
697 print('Invalid compute capability: ' % compute_capability)
698 all_valid = False
699
700 if all_valid:
701 break
702
703 # Reset and Retry
704 environ_cp['TF_CUDA_COMPUTE_CAPABILITIES'] = ''
705
706 # Set TF_CUDA_COMPUTE_CAPABILITIES
707 environ_cp['TF_CUDA_COMPUTE_CAPABILITIES'] = tf_cuda_compute_capabilities
708 write_action_env_to_bazelrc('TF_CUDA_COMPUTE_CAPABILITIES',
709 tf_cuda_compute_capabilities)
710
711
712def set_other_cuda_vars(environ_cp):
713 """Set other CUDA related variables."""
714 if is_windows():
715 # The following three variables are needed for MSVC toolchain configuration
716 # in Bazel
717 environ_cp['CUDA_PATH'] = environ_cp.get('CUDA_TOOLKIT_PATH')
718 environ_cp['CUDA_COMPUTE_CAPABILITIES'] = environ_cp.get(
719 'TF_CUDA_COMPUTE_CAPABILITIES')
720 environ_cp['NO_WHOLE_ARCHIVE_OPTION'] = 1
721 write_action_env_to_bazelrc('CUDA_PATH', environ_cp.get('CUDA_PATH'))
722 write_action_env_to_bazelrc('CUDA_COMPUTE_CAPABILITIE',
723 environ_cp.get('CUDA_COMPUTE_CAPABILITIE'))
724 write_action_env_to_bazelrc('NO_WHOLE_ARCHIVE_OPTION',
725 environ_cp.get('NO_WHOLE_ARCHIVE_OPTION'))
726 write_to_bazelrc('build --config=win-cuda')
727 write_to_bazelrc('test --config=win-cuda')
728 else:
729 # If CUDA is enabled, always use GPU during build and test.
730 if environ_cp.get('TF_CUDA_CLANG') == '1':
731 write_to_bazelrc('build --config=cuda_clang')
732 write_to_bazelrc('test --config=cuda_clang')
733 else:
734 write_to_bazelrc('build --config=cuda')
735 write_to_bazelrc('test --config=cuda')
736
737
738def set_host_cxx_compiler(environ_cp):
739 """Set HOST_CXX_COMPILER."""
740 default_cxx_host_compiler = run_shell('which g++ || true')
741 ask_cxx_host_compiler = (
742 'Please specify which C++ compiler should be used as'
743 ' the host C++ compiler. [Default is %s]: ') % default_cxx_host_compiler
744
745 while True:
746 host_cxx_compiler = get_from_env_or_user_or_default(
747 environ_cp, 'HOST_CXX_COMPILER', ask_cxx_host_compiler,
748 default_cxx_host_compiler)
749 if os.path.exists(host_cxx_compiler):
750 break
751
752 # Reset and retry
753 print('Invalid C++ compiler path. %s cannot be found' % host_cxx_compiler)
754 environ_cp['HOST_CXX_COMPILER'] = ''
755
756 # Set HOST_CXX_COMPILER
757 environ_cp['HOST_CXX_COMPILER'] = host_cxx_compiler
758 write_action_env_to_bazelrc('HOST_CXX_COMPILER', host_cxx_compiler)
759
760
761def set_host_c_compiler(environ_cp):
762 """Set HOST_C_COMPILER."""
763 default_c_host_compiler = run_shell('which gcc || true')
764 ask_c_host_compiler = (
765 'Please specify which C compiler should be used as the'
766 ' host C compiler. [Default is %s]: ') % default_c_host_compiler
767
768 while True:
769 host_c_compiler = get_from_env_or_user_or_default(
770 environ_cp, 'HOST_C_COMPILER', ask_c_host_compiler,
771 default_c_host_compiler)
772 if os.path.exists(host_c_compiler):
773 break
774
775 # Reset and retry
776 print('Invalid C compiler path. %s cannot be found' % host_c_compiler)
777 environ_cp['HOST_C_COMPILER'] = ''
778
779 # Set HOST_C_COMPILER
780 environ_cp['HOST_C_COMPILER'] = host_c_compiler
781 write_action_env_to_bazelrc('HOST_C_COMPILER', host_c_compiler)
782
783
784def set_computecpp_toolkit_path(environ_cp):
785 """Set COMPUTECPP_TOOLKIT_PATH."""
786 ask_computecpp_toolkit_path = ('Please specify the location where ComputeCpp '
787 'for SYCL %s is installed. [Default is %s]: '
788 ) % (_TF_OPENCL_VERSION,
789 _DEFAULT_COMPUTECPP_TOOLKIT_PATH)
790
791 while True:
792 computecpp_toolkit_path = get_from_env_or_user_or_default(
793 environ_cp, 'COMPUTECPP_TOOLKIT_PATH', ask_computecpp_toolkit_path,
794 _DEFAULT_COMPUTECPP_TOOLKIT_PATH)
795 if is_linux():
796 sycl_rt_lib_path = 'lib/libComputeCpp.so'
797 else:
798 sycl_rt_lib_path = ''
799
800 sycl_rt_lib_path_full = os.path.join(computecpp_toolkit_path,
801 sycl_rt_lib_path)
802 if os.path.exists(sycl_rt_lib_path_full):
803 break
804
805 print('Invalid SYCL %s library path. %s cannot be found' %
806 (_TF_OPENCL_VERSION, sycl_rt_lib_path_full))
807 environ_cp['COMPUTECPP_TOOLKIT_PATH'] = ''
808
809 # Set COMPUTECPP_TOOLKIT_PATH
810 environ_cp['COMPUTECPP_TOOLKIT_PATH'] = computecpp_toolkit_path
811 write_action_env_to_bazelrc('COMPUTECPP_TOOLKIT_PATH',
812 computecpp_toolkit_path)
813
814
815def set_mpi_home(environ_cp):
816 """Set MPI_HOME."""
817 cmd = ('dirname $(dirname $(which mpirun)) || dirname $(dirname $(which '
818 'mpiexec)) || true')
819 default_mpi_home = run_shell(cmd)
820 ask_mpi_home = ('Please specify the MPI toolkit folder. [Default is %s]: '
821 ) % default_mpi_home
822 while True:
823 mpi_home = get_from_env_or_user_or_default(environ_cp, 'MPI_HOME',
824 ask_mpi_home, default_mpi_home)
825
826 if os.path.exists(os.path.join(mpi_home, 'include')) and os.path.exists(
827 os.path.join(mpi_home, 'lib')):
828 break
829
830 print('Invalid path to the MPI Toolkit. %s or %s cannot be found' %
831 (os.path.join(mpi_home, 'include'),
832 os.path.exists(os.path.join(mpi_home, 'lib'))))
833 environ_cp['MPI_HOME'] = ''
834
835 # Set MPI_HOME
836 environ_cp['MPI_HOME'] = str(mpi_home)
837
838
839def set_other_mpi_vars(environ_cp):
840 """Set other MPI related variables."""
841 # Link the MPI header files
842 mpi_home = environ_cp.get('MPI_HOME')
843 symlink_force('%s/include/mpi.h' % mpi_home, 'third_party/mpi/mpi.h')
844
845 # Determine if we use OpenMPI or MVAPICH, these require different header files
846 # to be included here to make bazel dependency checker happy
847 if os.path.exists(os.path.join(mpi_home, 'include/mpi_portable_platform.h')):
848 symlink_force(
849 os.path.join(mpi_home, 'include/mpi_portable_platform.h'),
850 'third_party/mpi/mpi_portable_platform.h')
851 # TODO(gunan): avoid editing files in configure
852 sed_in_place('third_party/mpi/mpi.bzl', 'MPI_LIB_IS_OPENMPI=False',
853 'MPI_LIB_IS_OPENMPI=True')
854 else:
855 # MVAPICH / MPICH
856 symlink_force(
857 os.path.join(mpi_home, 'include/mpio.h'), 'third_party/mpi/mpio.h')
858 symlink_force(
859 os.path.join(mpi_home, 'include/mpicxx.h'), 'third_party/mpi/mpicxx.h')
860 # TODO(gunan): avoid editing files in configure
861 sed_in_place('third_party/mpi/mpi.bzl', 'MPI_LIB_IS_OPENMPI=True',
862 'MPI_LIB_IS_OPENMPI=False')
863
864 if os.path.exists(os.path.join(mpi_home, 'lib/libmpi.so')):
865 symlink_force(
866 os.path.join(mpi_home, 'lib/libmpi.so'), 'third_party/mpi/libmpi.so')
867 else:
868 raise ValueError('Cannot find the MPI library file in %s/lib' % mpi_home)
869
870
871def set_mkl():
872 write_to_bazelrc('build:mkl --define with_mkl_support=true')
873 write_to_bazelrc('build:mkl --define using_mkl=true')
874 write_to_bazelrc('build:mkl -c opt')
875 write_to_bazelrc('build:mkl --copt="-DEIGEN_USE_VML"')
876 print(
877 'Add "--config=mkl" to your bazel command to build with MKL '
878 'support.\nPlease note that MKL on MacOS or windows is still not '
879 'supported.\nIf you would like to use a local MKL instead of '
880 'downloading, please set the environment variable \"TF_MKL_ROOT\" every '
881 'time before build.')
882
883
884def main():
885 # Make a copy of os.environ to be clear when functions and getting and setting
886 # environment variables.
887 environ_cp = dict(os.environ)
888
889 check_bazel_version('0.4.5')
890
891 reset_tf_configure_bazelrc()
892 cleanup_makefile()
893 setup_python(environ_cp)
894 run_gen_git_source(environ_cp)
895
896 if is_windows():
897 environ_cp['TF_NEED_GCP'] = '0'
898 environ_cp['TF_NEED_HDFS'] = '0'
899 environ_cp['TF_NEED_JEMALLOC'] = '0'
900 environ_cp['TF_NEED_OPENCL'] = '0'
901 environ_cp['TF_CUDA_CLANG'] = '0'
902
903 if is_macos():
904 environ_cp['TF_NEED_JEMALLOC'] = '0'
905
906 set_build_var(environ_cp, 'TF_NEED_JEMALLOC', 'jemalloc as malloc',
907 'with_jemalloc', True)
908 set_build_var(environ_cp, 'TF_NEED_GCP', 'Google Cloud Platform',
909 'with_gcp_support', False)
910 set_build_var(environ_cp, 'TF_NEED_HDFS', 'Hadoop File System',
911 'with_hdfs_support', False)
912 set_build_var(environ_cp, 'TF_ENABLE_XLA', 'XLA JIT', 'with_xla_support',
913 False)
914 set_build_var(environ_cp, 'TF_NEED_VERBS', 'VERBS', 'with_verbs_support',
915 False)
916
917 set_action_env_var(environ_cp, 'TF_NEED_OPENCL', 'OpenCL', False)
918 if environ_cp.get('TF_NEED_OPENCL') == '1':
919 set_host_cxx_compiler(environ_cp)
920 set_host_c_compiler(environ_cp)
921 set_computecpp_toolkit_path(environ_cp)
922
923 set_action_env_var(environ_cp, 'TF_NEED_CUDA', 'CUDA', False)
924 if environ_cp.get('TF_NEED_CUDA') == '1':
925 set_tf_cuda_version(environ_cp)
926 set_tf_cunn_version(environ_cp)
927 set_tf_cuda_compute_capabilities(environ_cp)
928
929 set_tf_cuda_clang(environ_cp)
930 if environ_cp.get('TF_CUDA_CLANG') == '1':
931 # Set up which clang we should use as the cuda / host compiler.
932 set_clang_cuda_compiler_path(environ_cp)
933 else:
934 # Set up which gcc nvcc should use as the host compiler
935 # No need to set this on Windows
936 if not is_windows():
937 set_gcc_host_compiler_path(environ_cp)
938 set_other_cuda_vars(environ_cp)
939
940 set_build_var(environ_cp, 'TF_NEED_MPI', 'MPI', 'with_mpi_support', False)
941 if environ_cp.get('TF_NEED_MPI') == '1':
942 set_mpi_home(environ_cp)
943 set_other_mpi_vars(environ_cp)
944
945 set_cc_opt_flags(environ_cp)
946 set_mkl()
947
948
949if __name__ == '__main__':
950 main()