Skip to content

Commit aa91193

Browse files
peterjc123apaszke
authored andcommitted
Improve Windows Compatibility (for csrc/scripts) (pytorch#2941)
1 parent 1d57a2d commit aa91193

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+842
-379
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ torch/version.py
66
torch/csrc/generic/TensorMethods.cpp
77
torch/lib/*.so*
88
torch/lib/*.a*
9+
torch/lib/*.dll*
10+
torch/lib/*.lib
911
torch/lib/*.dylib*
1012
torch/lib/*.h
1113
torch/lib/build

cmake/FindCUDA/FindCUDA.cmake

+1-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ option(CUDA_HOST_COMPILATION_CPP "Generated file extension" ON)
488488
set(CUDA_NVCC_FLAGS "" CACHE STRING "Semi-colon delimit multiple arguments.")
489489

490490
if(CMAKE_GENERATOR MATCHES "Visual Studio")
491-
set(CUDA_HOST_COMPILER "$(VCInstallDir)bin" CACHE FILEPATH "Host side compiler used by NVCC")
491+
set(CUDA_HOST_COMPILER "${CMAKE_C_COMPILER}" CACHE FILEPATH "Host side compiler used by NVCC")
492492
else()
493493
if(APPLE
494494
AND "${CMAKE_C_COMPILER_ID}" MATCHES "Clang"

setup.py

+109-34
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@
1919
NCCL_INCLUDE_DIR, NCCL_ROOT_DIR, NCCL_SYSTEM_LIB
2020
from tools.setup_helpers.nnpack import WITH_NNPACK, NNPACK_LIB_PATHS, \
2121
NNPACK_INCLUDE_DIRS
22+
from tools.setup_helpers.nvtoolext import NVTOOLEXT_HOME
2223
from tools.setup_helpers.split_types import split_types
2324

2425
DEBUG = check_env_flag('DEBUG')
25-
WITH_DISTRIBUTED = not check_env_flag('NO_DISTRIBUTED')
26+
27+
IS_WINDOWS = (platform.system() == 'Windows')
28+
IS_DARWIN = (platform.system() == 'Darwin')
29+
IS_LINUX = (platform.system() == 'Linux')
30+
31+
WITH_DISTRIBUTED = not check_env_flag('NO_DISTRIBUTED') and not IS_WINDOWS
2632
WITH_DISTRIBUTED_MW = WITH_DISTRIBUTED and check_env_flag('WITH_DISTRIBUTED_MW')
2733

2834

@@ -82,14 +88,17 @@ def patched_link(self, *args, **kwargs):
8288

8389
dep_libs = [
8490
'nccl', 'ATen',
85-
'libshm', 'gloo', 'THD', 'nanopb',
91+
'libshm', 'libshm_windows', 'gloo', 'THD', 'nanopb',
8692
]
8793

8894

8995
def build_libs(libs):
9096
for lib in libs:
9197
assert lib in dep_libs, 'invalid lib: {}'.format(lib)
92-
build_libs_cmd = ['bash', 'torch/lib/build_libs.sh']
98+
if IS_WINDOWS:
99+
build_libs_cmd = ['torch\\lib\\build_libs.bat']
100+
else:
101+
build_libs_cmd = ['bash', 'torch/lib/build_libs.sh']
93102
my_env = os.environ.copy()
94103
my_env["PYTORCH_PYTHON"] = sys.executable
95104
if WITH_SYSTEM_NCCL:
@@ -119,7 +128,11 @@ def run(self):
119128
libs = []
120129
if WITH_NCCL and not WITH_SYSTEM_NCCL:
121130
libs += ['nccl']
122-
libs += ['ATen', 'libshm', 'nanopb']
131+
libs += ['ATen', 'nanopb']
132+
if IS_WINDOWS:
133+
libs += ['libshm_windows']
134+
else:
135+
libs += ['libshm']
123136
if WITH_DISTRIBUTED:
124137
if sys.platform.startswith('linux'):
125138
libs += ['gloo']
@@ -201,6 +214,7 @@ def monkey_patch_THD_link_flags():
201214
class build_ext(setuptools.command.build_ext.build_ext):
202215

203216
def run(self):
217+
204218
# Print build options
205219
if WITH_NUMPY:
206220
print('-- Building with NumPy bindings')
@@ -273,6 +287,25 @@ def run(self):
273287
'torch/lib/tmp_install/share/ATen/Declarations.yaml',
274288
jit_gen_dir)
275289

290+
if IS_WINDOWS:
291+
build_temp = self.build_temp
292+
build_dir = 'torch/csrc'
293+
294+
ext_filename = self.get_ext_filename('_C')
295+
lib_filename = '.'.join(ext_filename.split('.')[:-1]) + '.lib'
296+
297+
_C_LIB = os.path.join(build_temp, build_dir, lib_filename).replace('\\', '/')
298+
299+
THNN.extra_link_args += [_C_LIB]
300+
if WITH_CUDA:
301+
THCUNN.extra_link_args += [_C_LIB]
302+
else:
303+
# To generate .obj files for AutoGPU for the export class
304+
# a header file cannot build, so it has to be copied to someplace as a source file
305+
if os.path.exists("torch/csrc/generated/AutoGPU_cpu_win.cpp"):
306+
os.remove("torch/csrc/generated/AutoGPU_cpu_win.cpp")
307+
shutil.copyfile("torch/csrc/cuda/AutoGPU.h", "torch/csrc/generated/AutoGPU_cpu_win.cpp")
308+
276309
# It's an old-style class in Python 2.7...
277310
setuptools.command.build_ext.build_ext.run(self)
278311

@@ -315,14 +348,23 @@ def run(self):
315348
include_dirs = []
316349
library_dirs = []
317350
extra_link_args = []
318-
extra_compile_args = ['-std=c++11', '-Wno-write-strings',
319-
# Python 2.6 requires -fno-strict-aliasing, see
320-
# http://legacy.python.org/dev/peps/pep-3123/
321-
'-fno-strict-aliasing',
322-
# Clang has an unfixed bug leading to spurious missing
323-
# braces warnings, see
324-
# https://bugs.llvm.org/show_bug.cgi?id=21629
325-
'-Wno-missing-braces']
351+
352+
if IS_WINDOWS:
353+
extra_compile_args = ['/Z7', '/EHa', '/DNOMINMAX'
354+
# /Z7 turns on symbolic debugging information in .obj files
355+
# /EHa is about native C++ catch support for asynchronous
356+
# structured exception handling (SEH)
357+
# /DNOMINMAX removes builtin min/max functions
358+
]
359+
else:
360+
extra_compile_args = ['-std=c++11', '-Wno-write-strings',
361+
# Python 2.6 requires -fno-strict-aliasing, see
362+
# http://legacy.python.org/dev/peps/pep-3123/
363+
'-fno-strict-aliasing',
364+
# Clang has an unfixed bug leading to spurious missing
365+
# braces warnings, see
366+
# https://bugs.llvm.org/show_bug.cgi?id=21629
367+
'-Wno-missing-braces']
326368

327369
cwd = os.path.dirname(os.path.abspath(__file__))
328370
lib_path = os.path.join(cwd, "torch", "lib")
@@ -355,13 +397,18 @@ def check_file(f):
355397
ATEN_LIB = os.path.join(lib_path, 'libATen.so.1')
356398
THD_LIB = os.path.join(lib_path, 'libTHD.a')
357399
NCCL_LIB = os.path.join(lib_path, 'libnccl.so.1')
358-
if platform.system() == 'Darwin':
359-
ATEN_LIB = os.path.join(lib_path, 'libATen.1.dylib')
360-
NCCL_LIB = os.path.join(lib_path, 'libnccl.1.dylib')
361400

362401
# static library only
363402
NANOPB_STATIC_LIB = os.path.join(lib_path, 'libprotobuf-nanopb.a')
364403

404+
if IS_DARWIN:
405+
ATEN_LIB = os.path.join(lib_path, 'libATen.1.dylib')
406+
NCCL_LIB = os.path.join(lib_path, 'libnccl.1.dylib')
407+
408+
if IS_WINDOWS:
409+
ATEN_LIB = os.path.join(lib_path, 'ATen.lib')
410+
NANOPB_STATIC_LIB = os.path.join(lib_path, 'protobuf-nanopb.lib')
411+
365412
main_compile_args = ['-D_THP_CORE']
366413
main_libraries = ['shm']
367414
main_link_args = [ATEN_LIB, NANOPB_STATIC_LIB]
@@ -457,20 +504,41 @@ def check_file(f):
457504
include_dirs += [tmp_install_path + "/include/THD"]
458505
main_link_args += [THD_LIB]
459506

507+
if IS_WINDOWS and not WITH_CUDA:
508+
main_sources += ["torch/csrc/generated/AutoGPU_cpu_win.cpp"]
509+
460510
if WITH_CUDA:
461-
cuda_lib_dirs = ['lib64', 'lib']
511+
nvtoolext_lib_name = None
512+
if IS_WINDOWS:
513+
cuda_lib_path = CUDA_HOME + '/lib/x64/'
514+
nvtoolext_lib_path = NVTOOLEXT_HOME + '/lib/x64/'
515+
nvtoolext_include_path = os.path.join(NVTOOLEXT_HOME, 'include')
516+
517+
library_dirs.append(nvtoolext_lib_path)
518+
include_dirs.append(nvtoolext_include_path)
519+
520+
nvtoolext_lib_name = 'nvToolsExt64_1'
521+
522+
# MSVC doesn't support runtime symbol resolving, `nvrtc` and `cuda` should be linked
523+
main_libraries += ['nvrtc', 'cuda']
524+
else:
525+
cuda_lib_dirs = ['lib64', 'lib']
526+
527+
for lib_dir in cuda_lib_dirs:
528+
cuda_lib_path = os.path.join(CUDA_HOME, lib_dir)
529+
if os.path.exists(cuda_lib_path):
530+
break
531+
extra_link_args.append('-Wl,-rpath,' + cuda_lib_path)
532+
533+
nvtoolext_lib_name = 'nvToolsExt'
534+
535+
library_dirs.append(cuda_lib_path)
462536
cuda_include_path = os.path.join(CUDA_HOME, 'include')
463-
for lib_dir in cuda_lib_dirs:
464-
cuda_lib_path = os.path.join(CUDA_HOME, lib_dir)
465-
if os.path.exists(cuda_lib_path):
466-
break
467537
include_dirs.append(cuda_include_path)
468538
include_dirs.append(tmp_install_path + "/include/THCUNN")
469-
library_dirs.append(cuda_lib_path)
470-
extra_link_args.append('-Wl,-rpath,' + cuda_lib_path)
471539
extra_compile_args += ['-DWITH_CUDA']
472540
extra_compile_args += ['-DCUDA_LIB_PATH=' + cuda_lib_path]
473-
main_libraries += ['cudart', 'nvToolsExt']
541+
main_libraries += ['cudart', nvtoolext_lib_name]
474542
main_sources += [
475543
"torch/csrc/cuda/Module.cpp",
476544
"torch/csrc/cuda/Storage.cpp",
@@ -498,7 +566,8 @@ def check_file(f):
498566
library_dirs.append(CUDNN_LIB_DIR)
499567
# NOTE: these are at the front, in case there's another cuDNN in CUDA path
500568
include_dirs.insert(0, CUDNN_INCLUDE_DIR)
501-
extra_link_args.insert(0, '-Wl,-rpath,' + CUDNN_LIB_DIR)
569+
if not IS_WINDOWS:
570+
extra_link_args.insert(0, '-Wl,-rpath,' + CUDNN_LIB_DIR)
502571
main_sources += [
503572
"torch/csrc/cudnn/BatchNorm.cpp",
504573
"torch/csrc/cudnn/Conv.cpp",
@@ -519,8 +588,11 @@ def check_file(f):
519588
extra_compile_args += ['-DWITH_NNPACK']
520589

521590
if DEBUG:
522-
extra_compile_args += ['-O0', '-g']
523-
extra_link_args += ['-O0', '-g']
591+
if IS_WINDOWS:
592+
extra_link_args.append('/DEBUG:FULL')
593+
else:
594+
extra_compile_args += ['-O0', '-g']
595+
extra_link_args += ['-O0', '-g']
524596

525597
if os.getenv('PYTORCH_BINARY_BUILD') and platform.system() == 'Linux':
526598
print('PYTORCH_BINARY_BUILD found. Static linking libstdc++ on Linux')
@@ -537,8 +609,10 @@ def check_file(f):
537609

538610

539611
def make_relative_rpath(path):
540-
if platform.system() == 'Darwin':
612+
if IS_DARWIN:
541613
return '-Wl,-rpath,@loader_path/' + path
614+
elif IS_WINDOWS:
615+
return ''
542616
else:
543617
return '-Wl,-rpath,$ORIGIN/' + path
544618

@@ -559,11 +633,12 @@ def make_relative_rpath(path):
559633
)
560634
extensions.append(C)
561635

562-
DL = Extension("torch._dl",
563-
sources=["torch/csrc/dl.c"],
564-
language='c',
565-
)
566-
extensions.append(DL)
636+
if not IS_WINDOWS:
637+
DL = Extension("torch._dl",
638+
sources=["torch/csrc/dl.c"],
639+
language='c',
640+
)
641+
extensions.append(DL)
567642

568643
THNN = Extension("torch._thnn._THNN",
569644
sources=['torch/csrc/nn/THNN.cpp'],
@@ -579,7 +654,7 @@ def make_relative_rpath(path):
579654

580655
if WITH_CUDA:
581656
thnvrtc_link_flags = extra_link_args + [make_relative_rpath('lib')]
582-
if platform.system() == 'Linux':
657+
if IS_LINUX:
583658
thnvrtc_link_flags = ['-Wl,--no-as-needed'] + thnvrtc_link_flags
584659
THNVRTC = Extension("torch._nvrtc",
585660
libraries=['nvrtc', 'cuda'],
@@ -634,7 +709,7 @@ def make_relative_rpath(path):
634709
cmdclass=cmdclass,
635710
packages=packages,
636711
package_data={'torch': [
637-
'lib/*.so*', 'lib/*.dylib*',
712+
'lib/*.so*', 'lib/*.dylib*', 'lib/*.dll',
638713
'lib/torch_shm_manager',
639714
'lib/*.h',
640715
'lib/include/TH/*.h', 'lib/include/TH/generic/*.h',

test/common.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
import os
3+
import re
34
import argparse
45
import unittest
56
import warnings
@@ -320,6 +321,12 @@ def accept_output(update_type):
320321
("I got this output for {}:\n\n{}\n\n"
321322
"No expect file exists; to accept the current output, run:\n"
322323
"python {} {} --accept").format(munged_id, s, __main__.__file__, munged_id))
324+
325+
# a hack for JIT tests
326+
if sys.platform == 'win32':
327+
expected = re.sub(r'CppOp\[(.+?)\]', 'CppOp[]', expected)
328+
s = re.sub(r'CppOp\[(.+?)\]', 'CppOp[]', s)
329+
323330
if ACCEPT:
324331
if expected != s:
325332
return accept_output("updated output")

test/run_test.bat

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
@echo off
2+
3+
set PYCMD=python
4+
5+
echo Running JIT tests
6+
%PYCMD% test_jit.py
7+
8+
echo Running torch tests
9+
%PYCMD% test_torch.py
10+
11+
echo Running autograd tests
12+
%PYCMD% test_autograd.py
13+
%PYCMD% test_potrf.py
14+
15+
echo Running sparse tests
16+
%PYCMD% test_sparse.py
17+
18+
echo Running nn tests
19+
%PYCMD% test_nn.py
20+
21+
echo Running legacy nn tests
22+
%PYCMD% test_legacy_nn.py
23+
24+
echo Running optim tests
25+
%PYCMD% test_optim.py
26+
27+
echo Running multiprocessing tests
28+
%PYCMD% test_multiprocessing.py
29+
30+
echo Running util tests
31+
%PYCMD% test_utils.py
32+
33+
echo Running dataloader tests
34+
%PYCMD% test_dataloader.py
35+
36+
echo Running cuda tests
37+
%PYCMD% test_cuda.py
38+
39+
echo Running NCCL tests
40+
%PYCMD% test_nccl.py

test/test_multiprocessing.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@
2222
TEST_MULTIGPU = TEST_CUDA_IPC and torch.cuda.device_count() > 1
2323

2424

25+
class SubProcess(mp.Process):
26+
def __init__(self, tensor):
27+
super(SubProcess, self).__init__()
28+
self.tensor = tensor
29+
self.daemon = True
30+
31+
def run(self):
32+
self.tensor.add_(3)
33+
34+
2535
def simple_fill(queue, event):
2636
data = queue.get()
2737
data[0][:] = 4
@@ -269,15 +279,6 @@ def queue_put():
269279
queue_put()
270280

271281
def test_inherit_tensor(self):
272-
class SubProcess(mp.Process):
273-
def __init__(self, tensor):
274-
super(SubProcess, self).__init__()
275-
self.tensor = tensor
276-
self.daemon = True
277-
278-
def run(self):
279-
self.tensor.add_(3)
280-
281282
t = torch.zeros(5, 5)
282283
p = SubProcess(t.share_memory_())
283284
p.start()

test/test_utils.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ def init(cls):
342342
path = download_file('https://download.pytorch.org/test_data/legacy_modules.t7')
343343
except unittest.SkipTest:
344344
return
345-
tests = load_lua(path)
345+
long_size = 8 if sys.platform == 'win32' else None
346+
tests = load_lua(path, long_size=long_size)
346347
for name, test in tests['modules'].items():
347348
test_name = 'test_' + name.replace('nn.', '')
348349
setattr(cls, test_name, cls._module_test(name, test))

tools/autograd/templates/Functions.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#include "Functions.h"
22
#include <ATen/WrapDimUtils.h>
33

4+
// define constants like M_PI and C keywords for MSVC
5+
#ifdef _MSC_VER
6+
#define _USE_MATH_DEFINES
7+
#include <ciso646>
8+
#endif
49
#include <math.h>
510

611
// ${generated_comment}

0 commit comments

Comments
 (0)