@@ -3337,6 +3337,64 @@ def test_no_change(self):
33373337 # if the content does not change
33383338 self .assertEqual (pre_mtime , post_mtime )
33393339
3340+ TOUCH_CODE = dedent ("""
3341+ /*[clinic input]
3342+ module m
3343+ [clinic start generated code]*/
3344+
3345+ /*[clinic input]
3346+ output everything file
3347+ m.func
3348+ a: int
3349+ /
3350+
3351+ Docstring.
3352+ [clinic start generated code]*/
3353+ """ )
3354+
3355+ def test_touch_source (self ):
3356+ # gh-64595: The build system does not know that the source file
3357+ # depends on the file generated from it, so the modification
3358+ # times are updated to force the recompilation.
3359+ def mtimes ():
3360+ return os .stat (fn ).st_mtime_ns , os .stat (dest ).st_mtime_ns
3361+
3362+ def set_mtimes (source , generated ):
3363+ os .utime (fn , ns = (source , source ))
3364+ os .utime (dest , ns = (generated , generated ))
3365+
3366+ with os_helper .temp_dir () as tmp_dir :
3367+ fn = os .path .join (tmp_dir , "test.c" )
3368+ with open (fn , "w" , encoding = "utf-8" ) as f :
3369+ f .write (self .TOUCH_CODE )
3370+ dest = self .dest_file (fn )
3371+ self .expect_success (fn )
3372+ source_mtime , generated_mtime = mtimes ()
3373+ self .assertGreaterEqual (generated_mtime , source_mtime )
3374+
3375+ # The generated file is changed, so both files are touched.
3376+ os .unlink (dest )
3377+ old = source_mtime - 10 ** 10
3378+ os .utime (fn , ns = (old , old ))
3379+ self .expect_success (fn )
3380+ source_mtime , generated_mtime = mtimes ()
3381+ self .assertGreater (source_mtime , old )
3382+ self .assertGreaterEqual (generated_mtime , source_mtime )
3383+
3384+ # Nothing is changed, but the source file is newer, so only
3385+ # the generated file is touched.
3386+ set_mtimes (source_mtime - 10 ** 10 , source_mtime - 2 * 10 ** 10 )
3387+ old_source_mtime = os .stat (fn ).st_mtime_ns
3388+ self .expect_success (fn )
3389+ source_mtime , generated_mtime = mtimes ()
3390+ self .assertEqual (source_mtime , old_source_mtime )
3391+ self .assertGreaterEqual (generated_mtime , source_mtime )
3392+
3393+ # Nothing is changed and the generated file is newer,
3394+ # so no file is touched.
3395+ self .expect_success (fn )
3396+ self .assertEqual (mtimes (), (source_mtime , generated_mtime ))
3397+
33403398 def test_cli_force (self ):
33413399 invalid_input = dedent ("""
33423400 /*[clinic input]
0 commit comments