forked from pytorch/pytorch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nvcc_fix_deps.py
119 lines (92 loc) · 3.32 KB
/
nvcc_fix_deps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""Tool to fix the nvcc's dependecy file output
Usage: python nvcc_fix_deps.py nvcc [nvcc args]...
This wraps nvcc to ensure that the dependency file created by nvcc with the
-MD flag always uses absolute paths. nvcc sometimes outputs relative paths,
which ninja interprets as an unresolved dependency, so it triggers a rebuild
of that file every time.
The easiest way to use this is to define:
CMAKE_CUDA_COMPILER_LAUNCHER="python;tools/nvcc_fix_deps.py;ccache"
"""
import subprocess
import sys
from pathlib import Path
from typing import List, Optional, TextIO
def resolve_include(path: Path, include_dirs: List[Path]) -> Path:
for include_path in include_dirs:
abs_path = include_path / path
if abs_path.exists():
return abs_path
paths = "\n ".join(str(d / path) for d in include_dirs)
raise RuntimeError(
f"""
ERROR: Failed to resolve dependency:
{path}
Tried the following paths, but none existed:
{paths}
"""
)
def repair_depfile(depfile: TextIO, include_dirs: List[Path]) -> None:
changes_made = False
out = ""
for line in depfile:
if ":" in line:
colon_pos = line.rfind(":")
out += line[: colon_pos + 1]
line = line[colon_pos + 1 :]
line = line.strip()
if line.endswith("\\"):
end = " \\"
line = line[:-1].strip()
else:
end = ""
path = Path(line)
if not path.is_absolute():
changes_made = True
path = resolve_include(path, include_dirs)
out += f" {path}{end}\n"
# If any paths were changed, rewrite the entire file
if changes_made:
depfile.seek(0)
depfile.write(out)
depfile.truncate()
PRE_INCLUDE_ARGS = ["-include", "--pre-include"]
POST_INCLUDE_ARGS = ["-I", "--include-path", "-isystem", "--system-include"]
def extract_include_arg(include_dirs: List[Path], i: int, args: List[str]) -> None:
def extract_one(name: str, i: int, args: List[str]) -> Optional[str]:
arg = args[i]
if arg == name:
return args[i + 1]
if arg.startswith(name):
arg = arg[len(name) :]
return arg[1:] if arg[0] == "=" else arg
return None
for name in PRE_INCLUDE_ARGS:
path = extract_one(name, i, args)
if path is not None:
include_dirs.insert(0, Path(path).resolve())
return
for name in POST_INCLUDE_ARGS:
path = extract_one(name, i, args)
if path is not None:
include_dirs.append(Path(path).resolve())
return
if __name__ == "__main__":
ret = subprocess.run(
sys.argv[1:], stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr
)
depfile_path = None
include_dirs = []
# Parse only the nvcc arguments we care about
args = sys.argv[2:]
for i, arg in enumerate(args):
if arg == "-MF":
depfile_path = Path(args[i + 1])
elif arg == "-c":
# Include the base path of the cuda file
include_dirs.append(Path(args[i + 1]).resolve().parent)
else:
extract_include_arg(include_dirs, i, args)
if depfile_path is not None and depfile_path.exists():
with depfile_path.open("r+") as f:
repair_depfile(f, include_dirs)
sys.exit(ret.returncode)