mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 16:16:39 +00:00

f18's module files are Fortran with a leading header comment containing the module file format version and a hash of the following contents. This hash is currently used only to protect module files against corruption and truncation. Extend the use of these hashes to catch or avoid some error cases. When one module file depends upon another, note its hash in additional module file header comments. This allows the compiler to detect when the module dependency is on a module file that has been updated. Further, it allows the compiler to find the right module file dependency when the same module file name appears in multiple directories on the module search path. The order in which module files are written, when multiple modules appear in a source file, is such that every dependency is written before the module(s) that depend upon it, so that their hashes are known. A warning is emitted when a module file is not the first hit on the module file search path. Further work is needed to add a compiler option that emits (larger) stand-alone module files that incorporate copies of their dependencies rather than relying on search paths. This will be desirable for application libraries that want to ship only "top-level" module files without needing to include their dependencies. Another future work item would be to admit multiple modules in the same compilation with the same name if they have distinct hashes.
99 lines
3.0 KiB
Python
Executable File
99 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""Compiles a source file and compares generated .mod files against expected.
|
|
|
|
Parameters:
|
|
sys.argv[1]: a source file with contains the input and expected output
|
|
sys.argv[2]: the Flang frontend driver
|
|
sys.argv[3:]: Optional arguments to the Flang frontend driver"""
|
|
|
|
import sys
|
|
import re
|
|
import os
|
|
import tempfile
|
|
import subprocess
|
|
import glob
|
|
import common as cm
|
|
|
|
from pathlib import Path
|
|
from difflib import unified_diff
|
|
|
|
cm.check_args_long(sys.argv)
|
|
srcdir = Path(sys.argv[1])
|
|
sources = list(glob.iglob(str(srcdir)))
|
|
sources = sorted(sources)
|
|
diffs = ""
|
|
|
|
flang_fc1 = cm.set_executable(sys.argv[2])
|
|
flang_fc_args = sys.argv[3:]
|
|
flang_fc1_options = "-fsyntax-only"
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
for src in sources:
|
|
src = Path(src).resolve()
|
|
actual = ""
|
|
expect = ""
|
|
expected_files = set()
|
|
actual_files = set()
|
|
|
|
if not src.is_file():
|
|
cm.die(src)
|
|
|
|
prev_files = set(os.listdir(tmpdir))
|
|
cmd = [flang_fc1, *flang_fc_args, flang_fc1_options, str(src)]
|
|
proc = subprocess.check_output(
|
|
cmd, stderr=subprocess.PIPE, universal_newlines=True, cwd=tmpdir
|
|
)
|
|
actual_files = set(os.listdir(tmpdir)).difference(prev_files)
|
|
|
|
# The first 3 bytes of the files are an UTF-8 BOM
|
|
with open(src, "r", encoding="utf-8", errors="strict") as f:
|
|
for line in f:
|
|
m = re.search(r"^!Expect: (.*)", line)
|
|
if m:
|
|
expected_files.add(m.group(1))
|
|
|
|
extra_files = actual_files.difference(expected_files)
|
|
if extra_files:
|
|
print(f"Unexpected .mod files produced: {extra_files}")
|
|
sys.exit(1)
|
|
|
|
for mod in expected_files:
|
|
mod = Path(tmpdir).joinpath(mod)
|
|
if not mod.is_file():
|
|
print(f"Compilation did not produce expected mod file: {mod}")
|
|
sys.exit(1)
|
|
with open(mod, "r", encoding="utf-8", errors="strict") as f:
|
|
for line in f:
|
|
if "!mod$" in line or "!need$" in line:
|
|
continue
|
|
actual += line
|
|
|
|
with open(src, "r", encoding="utf-8", errors="strict") as f:
|
|
for line in f:
|
|
if f"!Expect: {mod.name}" in line:
|
|
for line in f:
|
|
if re.match(r"^$", line):
|
|
break
|
|
m = re.sub(r"^!", "", line.lstrip())
|
|
expect += m
|
|
|
|
diffs = "\n".join(
|
|
unified_diff(
|
|
actual.replace(" ", "").split("\n"),
|
|
expect.replace(" ", "").split("\n"),
|
|
fromfile=mod.name,
|
|
tofile="Expect",
|
|
n=999999,
|
|
)
|
|
)
|
|
|
|
if diffs != "":
|
|
print(diffs)
|
|
print()
|
|
print("FAIL")
|
|
sys.exit(1)
|
|
|
|
print()
|
|
print("PASS")
|