From: Ben Boeckel <ben.boeckel@kitware.com>
To: gcc-patches@gcc.gnu.org
Cc: Ben Boeckel <ben.boeckel@kitware.com>,
jason@redhat.com, nathan@acm.org, fortran@gcc.gnu.org,
gcc@gcc.gnu.org, brad.king@kitware.com
Subject: [PATCH v7 3/4] c++modules: report imported CMI files as dependencies
Date: Sun, 2 Jul 2023 12:32:10 -0400 [thread overview]
Message-ID: <20230702163211.3396210-4-ben.boeckel@kitware.com> (raw)
In-Reply-To: <20230702163211.3396210-1-ben.boeckel@kitware.com>
They affect the build, so report them via `-MF` mechanisms.
gcc/cp/
* module.cc (do_import): Report imported CMI files as
dependencies.
gcc/testsuite/
* g++.dg/modules/depreport-1_a.C: New test.
* g++.dg/modules/depreport-1_b.C: New test.
* g++.dg/modules/test-depfile.py: New tool for validating depfile
information.
* lib/modules.exp: Support for validating depfile contents.
Signed-off-by: Ben Boeckel <ben.boeckel@kitware.com>
---
gcc/cp/module.cc | 3 +
gcc/testsuite/g++.dg/modules/depreport-1_a.C | 10 +
gcc/testsuite/g++.dg/modules/depreport-1_b.C | 12 ++
gcc/testsuite/g++.dg/modules/test-depfile.py | 187 +++++++++++++++++++
gcc/testsuite/lib/modules.exp | 29 +++
5 files changed, 241 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/modules/depreport-1_a.C
create mode 100644 gcc/testsuite/g++.dg/modules/depreport-1_b.C
create mode 100644 gcc/testsuite/g++.dg/modules/test-depfile.py
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 9df60d695b1..f3acc4e02fe 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -18968,6 +18968,9 @@ module_state::do_import (cpp_reader *reader, bool outermost)
dump () && dump ("CMI is %s", file);
if (note_module_cmi_yes || inform_cmi_p)
inform (loc, "reading CMI %qs", file);
+ /* Add the CMI file to the dependency tracking. */
+ if (cpp_get_deps (reader))
+ deps_add_dep (cpp_get_deps (reader), file);
fd = open (file, O_RDONLY | O_CLOEXEC | O_BINARY);
e = errno;
}
diff --git a/gcc/testsuite/g++.dg/modules/depreport-1_a.C b/gcc/testsuite/g++.dg/modules/depreport-1_a.C
new file mode 100644
index 00000000000..241701728a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/depreport-1_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo;
+// { dg-module-cmi Foo }
+
+export class Base
+{
+public:
+ int m;
+};
diff --git a/gcc/testsuite/g++.dg/modules/depreport-1_b.C b/gcc/testsuite/g++.dg/modules/depreport-1_b.C
new file mode 100644
index 00000000000..b6e317c6703
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/depreport-1_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodules-ts }
+// { dg-additional-options -MD }
+// { dg-additional-options "-MF depreport-1.d" }
+
+import Foo;
+
+void foo ()
+{
+ Base b;
+}
+
+// { dg-final { run-check-module-dep-expect-input "depreport-1.d" "gcm.cache/Foo.gcm" } }
diff --git a/gcc/testsuite/g++.dg/modules/test-depfile.py b/gcc/testsuite/g++.dg/modules/test-depfile.py
new file mode 100644
index 00000000000..ea4edb61434
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/test-depfile.py
@@ -0,0 +1,187 @@
+import json
+
+
+# Parameters.
+ALL_ERRORS = False
+
+
+def _report_error(msg):
+ '''Report an error.'''
+ full_msg = 'ERROR: ' + msg
+ if ALL_ERRORS:
+ print(full_msg)
+ else:
+ raise RuntimeError(full_msg)
+
+
+class Token(object):
+ pass
+
+
+class Output(Token):
+ def __init__(self, path):
+ self.path = path
+
+
+class Input(Token):
+ def __init__(self, path):
+ self.path = path
+
+
+class Colon(Token):
+ pass
+
+
+class Append(Token):
+ pass
+
+
+class Variable(Token):
+ def __init__(self, name):
+ self.name = name
+
+
+class Word(Token):
+ def __init__(self, name):
+ self.name = name
+
+
+def validate_depfile(depfile, expect_input=None):
+ '''Validate a depfile contains some information
+
+ Returns `False` if the information is not found.
+ '''
+ with open(depfile, 'r') as fin:
+ depfile_content = fin.read()
+
+ real_lines = []
+ join_line = False
+ for line in depfile_content.split('\n'):
+ # Join the line if needed.
+ if join_line:
+ line = real_lines.pop() + line
+
+ # Detect line continuations.
+ join_line = line.endswith('\\')
+ # Strip line continuation characters.
+ if join_line:
+ line = line[:-1]
+
+ # Add to the real line set.
+ real_lines.append(line)
+
+ # Perform tokenization.
+ tokenized_lines = []
+ for line in real_lines:
+ tokenized = []
+ join_word = False
+ for word in line.split(' '):
+ if join_word:
+ word = tokenized.pop() + ' ' + word
+
+ # Detect word joins.
+ join_word = word.endswith('\\')
+ # Strip escape character.
+ if join_word:
+ word = word[:-1]
+
+ # Detect `:` at the end of a word.
+ if word.endswith(':'):
+ tokenized.append(word[:-1])
+ word = word[-1]
+
+ # Add word to the tokenized set.
+ tokenized.append(word)
+
+ tokenized_lines.append(tokenized)
+
+ # Parse.
+ ast = []
+ for line in tokenized_lines:
+ kind = None
+ for token in line:
+ if token == ':':
+ kind = 'dependency'
+ elif token == '+=':
+ kind = 'append'
+ if line == ['']:
+ kind = 'empty'
+
+ if kind is None:
+ _report_error('unknown line kind: %s' % line)
+
+ line_parse = []
+ if kind == 'dependency':
+ after_colon = False
+ for token in line:
+ if token == ':':
+ after_colon = True
+ elif after_colon:
+ line_parse.append(Input(token))
+ else:
+ line_parse.append(Output(token))
+ elif kind == 'append':
+ after_op = False
+ for token in line:
+ if token == '+=':
+ after_op = True
+ elif after_op:
+ line_parse.append(Word(token))
+ else:
+ line_parse.append(Variable(token))
+
+ ast.append(line_parse)
+
+ for node in ast:
+ for token in node:
+ if expect_input is not None:
+ # If the input is found, clear the expectation.
+ if isinstance(token, Input) and token.path == expect_input:
+ expect_input = None
+
+ result = True
+ if expect_input:
+ _report_error('missing input: %s' % expect_input)
+ result = False
+
+ return result
+
+
+if __name__ == '__main__':
+ import sys
+
+ depfile = None
+ have_expect = False
+ expect_input = None
+
+ # Parse arguments.
+ args = sys.argv[1:]
+ while args:
+ # Take an argument.
+ arg = args.pop(0)
+
+ # Flag to change how errors are reported.
+ if arg == '-A' or arg == '--all':
+ ALL_ERRORS = True
+ # Required arguments.
+ elif arg == '-d' or arg == '--depfile':
+ depfile = args.pop(0)
+ elif arg == '-i' or arg == '--expect-input':
+ expect_input = args.pop(0)
+ have_expect = True
+
+ # Validate that we have the required arguments.
+ if depfile is None:
+ raise RuntimeError('missing "depfile" file')
+ if have_expect is None:
+ raise RuntimeError('missing an "expect" argument')
+
+ # Do the actual work.
+ try:
+ is_ok = validate_depfile(depfile, expect_input=expect_input)
+ except BaseException as e:
+ _report_error('exception: %s' % e)
+
+ # Fail if errors are found.
+ if not is_ok:
+ sys.exit(1)
diff --git a/gcc/testsuite/lib/modules.exp b/gcc/testsuite/lib/modules.exp
index d466a73cbe1..e24ee7618d9 100644
--- a/gcc/testsuite/lib/modules.exp
+++ b/gcc/testsuite/lib/modules.exp
@@ -69,3 +69,32 @@ proc run-check-p1689-valid { depfile template } {
clean-p1689 $testcase
}
+
+proc run-check-module-dep { depfile flag expected } {
+ global srcdir subdir
+ # Extract the test file name from the arguments.
+ set testcase [file rootname [file tail $depfile]]
+
+ verbose "Verifying dependencies for $testcase in $srcdir/$subdir" 2
+ set testcase [remote_download host $testcase]
+
+ set pytest_script "test-depfile.py"
+ if { ![check_effective_target_recent_python3] } {
+ unsupported "$pytest_script python3 is missing"
+ return
+ }
+
+ verbose "running script test-depfile.py" 1
+ spawn -noecho python3 $srcdir/$subdir/$pytest_script --all --depfile $depfile $flag $expected
+
+ expect {
+ -re "ERROR: (\[^\r\n\]*)" {
+ fail $expect_out(0,string)
+ exp_continue
+ }
+ }
+}
+
+proc run-check-module-dep-expect-input { depfile expected } {
+ run-check-module-dep $depfile "--expect-input" $expected
+}
--
2.40.1
next prev parent reply other threads:[~2023-07-02 16:32 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-02 16:32 [PATCH v7 0/4] P1689R5 support Ben Boeckel
2023-07-02 16:32 ` [PATCH v7 1/4] spec: add a spec function to join arguments Ben Boeckel
2023-08-23 19:29 ` [PATCH v7 1/4] driver: " Jason Merrill
2023-08-23 21:29 ` Joseph Myers
2023-07-02 16:32 ` [PATCH v7 2/4] p1689r5: initial support Ben Boeckel
2023-08-23 19:37 ` Jason Merrill
2023-07-02 16:32 ` Ben Boeckel [this message]
2023-07-02 16:32 ` [PATCH v7 4/4] c++modules: report module mapper files as a dependency Ben Boeckel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230702163211.3396210-4-ben.boeckel@kitware.com \
--to=ben.boeckel@kitware.com \
--cc=brad.king@kitware.com \
--cc=fortran@gcc.gnu.org \
--cc=gcc-patches@gcc.gnu.org \
--cc=gcc@gcc.gnu.org \
--cc=jason@redhat.com \
--cc=nathan@acm.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).