|
| 1 | +import os.path |
| 2 | +import re, sys |
| 3 | + |
| 4 | +from . import common as _common |
| 5 | +from . import gcc as _gcc |
| 6 | + |
| 7 | +_normpath = _gcc._normpath |
| 8 | + |
| 9 | +TOOL = 'clang' |
| 10 | + |
| 11 | +META_FILES = { |
| 12 | + '<built-in>', |
| 13 | + '<command line>', |
| 14 | +} |
| 15 | + |
| 16 | + |
| 17 | +def preprocess(filename, |
| 18 | + incldirs=None, |
| 19 | + includes=None, |
| 20 | + macros=None, |
| 21 | + samefiles=None, |
| 22 | + cwd=None, |
| 23 | + ): |
| 24 | + if not cwd or not os.path.isabs(cwd): |
| 25 | + cwd = os.path.abspath(cwd or '.') |
| 26 | + filename = _normpath(filename, cwd) |
| 27 | + |
| 28 | + postargs = _gcc.POST_ARGS |
| 29 | + basename = os.path.basename(filename) |
| 30 | + dirname = os.path.basename(os.path.dirname(filename)) |
| 31 | + if (basename not in _gcc.FILES_WITHOUT_INTERNAL_CAPI |
| 32 | + and dirname not in _gcc.DIRS_WITHOUT_INTERNAL_CAPI): |
| 33 | + postargs += ('-DPy_BUILD_CORE=1',) |
| 34 | + |
| 35 | + text = _common.preprocess( |
| 36 | + TOOL, |
| 37 | + filename, |
| 38 | + incldirs=incldirs, |
| 39 | + includes=includes, |
| 40 | + macros=macros, |
| 41 | + #preargs=PRE_ARGS, |
| 42 | + postargs=postargs, |
| 43 | + executable=['clang'], |
| 44 | + compiler='unix', |
| 45 | + cwd=cwd, |
| 46 | + ) |
| 47 | + return _iter_lines(text, filename, samefiles, cwd) |
| 48 | + |
| 49 | + |
| 50 | +EXIT_MARKERS = {'# 2 "<built-in>" 2', '# 3 "<built-in>" 2', '# 4 "<built-in>" 2'} |
| 51 | + |
| 52 | + |
| 53 | +def _iter_lines(text, reqfile, samefiles, cwd, raw=False): |
| 54 | + lines = iter(text.splitlines()) |
| 55 | + |
| 56 | + # The first line is special. |
| 57 | + # The subsequent lines are consistent. |
| 58 | + firstlines = [ |
| 59 | + f'# 1 "{reqfile}"', |
| 60 | + '# 1 "<built-in>" 1', |
| 61 | + '# 1 "<built-in>" 3', |
| 62 | + '# 370 "<built-in>" 3', |
| 63 | + '# 1 "<command line>" 1', |
| 64 | + '# 1 "<built-in>" 2', |
| 65 | + ] |
| 66 | + for expected in firstlines: |
| 67 | + line = next(lines) |
| 68 | + if line != expected: |
| 69 | + raise NotImplementedError((line, expected)) |
| 70 | + |
| 71 | + # Do all the CLI-provided includes. |
| 72 | + filter_reqfile = (lambda f: _gcc._filter_reqfile(f, reqfile, samefiles)) |
| 73 | + make_info = (lambda lno: _common.FileInfo(reqfile, lno)) |
| 74 | + last = None |
| 75 | + for line in lines: |
| 76 | + assert last != reqfile, (last,) |
| 77 | + # NOTE:condition is clang specific |
| 78 | + if not line: |
| 79 | + continue |
| 80 | + lno, included, flags = _gcc._parse_marker_line(line, reqfile) |
| 81 | + if not included: |
| 82 | + raise NotImplementedError((line,)) |
| 83 | + if included == reqfile: |
| 84 | + # This will be the last one. |
| 85 | + assert 2 in flags, (line, flags) |
| 86 | + else: |
| 87 | + # NOTE:first condition is specific to clang |
| 88 | + if _normpath(included, cwd) == reqfile: |
| 89 | + assert 1 in flags or 2 in flags, (line, flags, included, reqfile) |
| 90 | + else: |
| 91 | + assert 1 in flags, (line, flags, included, reqfile) |
| 92 | + yield from _gcc._iter_top_include_lines( |
| 93 | + lines, |
| 94 | + _normpath(included, cwd), |
| 95 | + cwd, |
| 96 | + filter_reqfile, |
| 97 | + make_info, |
| 98 | + raw, |
| 99 | + EXIT_MARKERS |
| 100 | + ) |
| 101 | + last = included |
| 102 | + # The last one is always the requested file. |
| 103 | + # NOTE:_normpath is clang specific |
| 104 | + assert _normpath(included, cwd) == reqfile, (line,) |
0 commit comments