From d71a6cf829c22606c7dc687a9806ab573d454a09 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Fri, 4 Oct 2019 15:37:44 +0200
Subject: [PATCH] fix(build): Fix module changes not getting picked up

Previously, we left out the dependency of the QSTR header on
`modules.h`.  This was done to prevent rebuilds of the entire
MicroPython sources whenever a Pycardium module is changed. This
leads to issues where QSTRs got out of sync and weird errors like
the following could happen:

    import foo_module

    Exception: No module `abc_def` (a different string than expected)

Attempt to fix this by only updating the QSTR header when the
module-header actually changes.  For this, a few workarounds are needed:

- Replace symlinks with actual copied files so timestamps change on
  updates.
- Add a hack so meson picks up on the dependency of the file in genhdr/
- Rename the outer file so older meson versions don't complain about
  multiple targets with the same name.

Co-authored-by: dx <dequis@dequis.org>
Signed-off-by: Rahix <rahix@rahix.de>
---
 lib/micropython/gen-modules.py | 50 ++++++++++++++++++++++++----------
 lib/micropython/gen-qstr.sh    |  2 --
 pycardium/genhdr/meson.build   |  6 ++++
 pycardium/meson.build          |  5 +++-
 4 files changed, 45 insertions(+), 18 deletions(-)
 create mode 100644 pycardium/genhdr/meson.build

diff --git a/lib/micropython/gen-modules.py b/lib/micropython/gen-modules.py
index 64868e33e..805c80c78 100644
--- a/lib/micropython/gen-modules.py
+++ b/lib/micropython/gen-modules.py
@@ -3,6 +3,8 @@
 
 import sys
 import os
+import tempfile
+import shutil
 
 
 def main():
@@ -16,23 +18,41 @@ def main():
         modules |= makemoduledefs.find_module_registrations(source)
 
     stdout = sys.stdout
-    with open(sys.argv[2], "w") as f:
-        sys.stdout = f
+    with tempfile.TemporaryFile("w+") as temp:
+        sys.stdout = temp
         makemoduledefs.generate_module_table_header(sorted(modules))
-    sys.stdout = stdout
+        sys.stdout = stdout
+
+        # Read contents of existing file and compare
+        try:
+            with open(sys.argv[2], "r") as f:
+                old_content = f.read()
+        except FileNotFoundError:
+            old_content = ""
+
+        temp.seek(0)
+        new_content = temp.read()
+
+        if new_content == old_content:
+            # If both file contain the same content, exit early
+            sys.exit(0)
 
-    try:
-        os.mkdir(os.path.dirname(sys.argv[2]) + "/genhdr")
-    except FileExistsError:
-        pass
-
-    linkname = os.path.dirname(sys.argv[2]) + "/genhdr/" + os.path.basename(sys.argv[2])
-    if os.path.exists(linkname):
-        os.unlink(linkname)
-    os.symlink(
-        "../" + os.path.basename(sys.argv[2]),
-        linkname,
-    )
+        with open(sys.argv[2], "w") as f:
+            f.write(new_content)
+
+        try:
+            os.mkdir(os.path.dirname(sys.argv[2]) + "/genhdr")
+        except FileExistsError:
+            pass
+
+        linkname = (
+            os.path.dirname(sys.argv[2]) + "/genhdr/" + os.path.basename(sys.argv[2])
+        )
+        if os.path.exists(linkname):
+            os.unlink(linkname)
+        shutil.copy(sys.argv[2], linkname)
+
+    sys.stdout = stdout
 
 
 if __name__ == "__main__":
diff --git a/lib/micropython/gen-qstr.sh b/lib/micropython/gen-qstr.sh
index dda7d4577..78ecf8513 100755
--- a/lib/micropython/gen-qstr.sh
+++ b/lib/micropython/gen-qstr.sh
@@ -11,8 +11,6 @@ shift 5
 
 OUTPUT_DIR="$(dirname "$OUTPUT")"
 
-mkdir -p "$OUTPUT_DIR/genhdr"
-ln -sf "$(realpath --relative-to="$OUTPUT_DIR/genhdr" "$OUTPUT")" "$OUTPUT_DIR/genhdr/$(basename "$OUTPUT")"
 
 # call gcc -E to generate qstr.i.last
 gcc -E -DNO_QSTR -I"$SOURCE_DIR/micropython" -I"$PROJECT_SRC" -I"$OUTPUT_DIR" "$@" >"$OUTPUT_DIR/qstr.i.last"
diff --git a/pycardium/genhdr/meson.build b/pycardium/genhdr/meson.build
new file mode 100644
index 000000000..a130c8642
--- /dev/null
+++ b/pycardium/genhdr/meson.build
@@ -0,0 +1,6 @@
+qstr_genhdr_h = custom_target(
+  'genhdr-qstrdefs.generated.h',
+  output: 'qstrdefs.generated.h',
+  input: qstr_h,
+  command: ['cp', '@INPUT@', '@OUTPUT@'],
+)
diff --git a/pycardium/meson.build b/pycardium/meson.build
index b63404b7c..e50b61dfd 100644
--- a/pycardium/meson.build
+++ b/pycardium/meson.build
@@ -43,6 +43,7 @@ qstr_h = custom_target(
   input: [
     'modules/qstrdefs.h',
     'mpconfigport.h',
+    modules_h,
     micropython_sources,
     micropython_extmod_sources,
   ],
@@ -50,7 +51,9 @@ qstr_h = custom_target(
   command: [micropython_gen_qstr, meson.current_source_dir(), '@OUTPUT@', '@INPUT@'],
 )
 
-mp_headers = [version_h, modules_h, qstr_h]
+subdir('./genhdr')
+
+mp_headers = [version_h, modules_h, qstr_h, qstr_genhdr_h]
 
 #################################
 #    Python Frozen Modules      #
-- 
GitLab