diff --git a/lib/micropython/gen-modules.py b/lib/micropython/gen-modules.py
index 64868e33e48f693ad7d9103e6590e3e83350407f..805c80c78b9d1da538c79095f270783686f54ace 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 dda7d45772120ef9443a7ae896ef39a0c17c7bfb..78ecf851363be7946005203330b18402bfd3aed5 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 0000000000000000000000000000000000000000..a130c8642e0a4728451af8d68537b3252966f294
--- /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 b63404b7cce7d0be7263cc5fa0b6944de0de5642..e50b61dfdd69bcc7c104c94123329881e59dae2f 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      #