11package config
22
33import (
4+ "bufio"
5+ "maps"
46 "os"
57 "path/filepath"
8+ "slices"
9+ "sort"
610 "strings"
711
812 "github.com/goplus/lib/c/clang"
@@ -41,54 +45,49 @@ func PkgHfileInfo(includes []string, args []string, mix bool) *PkgHfilesInfo {
4145 }
4246 defer os .Remove (outfile .Name ())
4347
44- refMap := make (map [string ]int , len (includes ))
48+ mmOutput , err := os .CreateTemp ("" , "mmoutput_*" )
49+ if err != nil {
50+ panic (err )
51+ }
52+ defer os .Remove (mmOutput .Name ())
4553
4654 clangtool .ComposeIncludes (includes , outfile .Name ())
4755 index , unit , err := clangutils .CreateTranslationUnit (& clangutils.Config {
4856 File : outfile .Name (),
4957 Temp : false ,
50- Args : args ,
58+ Args : append ( args , "-MMD" , "-MF" , mmOutput . Name ()) ,
5159 })
60+
5261 defer unit .Dispose ()
5362 defer index .Dispose ()
5463 if err != nil {
5564 panic (err )
5665 }
5766
67+ inters := ParseMMOutout (outfile .Name (), mmOutput )
68+ var others []string
69+
5870 clangutils .GetInclusions (unit , func (inced clang.File , incins []clang.SourceLocation ) {
5971 // not in the first level include maybe impl or third hfile
6072 filename := filepath .Clean (clang .GoString (inced .FileName ()))
6173
62- if len (incins ) == 1 {
63- info .Inters = append (info .Inters , filename )
64- }
65-
66- ref , ok := refMap [filename ]
67- if ! ok {
68- refMap [filename ] = len (incins )
74+ // skip the composed header
75+ if filename == outfile .Name () {
6976 return
7077 }
71- // Handle duplicate references: Retain only the reference with the smallest source location.
72- // Example:
73- // temp1.h: temp2 tempimpl.h
74- // temp2.h: temp2
75- // The reference count for temp2.h should be 1 (not 2).
76- // If its count is 2, decrement it to 1.
77- if len (incins ) < ref {
78- refMap [filename ] = len (incins )
78+ if _ , ok := inters [filename ]; ! ok {
79+ others = append (others , filename )
7980 }
8081 })
8182
83+ info .Inters = slices .Collect (maps .Keys (inters ))
84+
8285 absLongestPrefix , err := filepath .Abs (CommonParentDir (info .Inters ))
8386 if err != nil {
8487 panic (err )
8588 }
8689
87- for filename , ref := range refMap {
88- if ref == 1 {
89- continue
90- }
91-
90+ for _ , filename := range others {
9291 if mix {
9392 info .Thirds = append (info .Thirds , filename )
9493 continue
@@ -104,6 +103,9 @@ func PkgHfileInfo(includes []string, args []string, mix bool) *PkgHfilesInfo {
104103 }
105104 }
106105
106+ sort .Strings (info .Inters )
107+ sort .Strings (info .Impls )
108+
107109 return info
108110}
109111
@@ -128,3 +130,22 @@ func CommonParentDir(paths []string) string {
128130 }
129131 return filepath .Dir (paths [0 ])
130132}
133+
134+ func ParseMMOutout (composedHeaderFileName string , outputFile * os.File ) (inters map [string ]struct {}) {
135+ scanner := bufio .NewScanner (outputFile )
136+
137+ fileName := strings .TrimSuffix (filepath .Base (composedHeaderFileName ), ".h" )
138+
139+ inters = make (map [string ]struct {})
140+
141+ for scanner .Scan () {
142+ // skip composed header file
143+ if strings .Contains (scanner .Text (), fileName ) {
144+ continue
145+ }
146+ inter := filepath .Clean (strings .TrimSpace (strings .TrimSuffix (scanner .Text (), `\` )))
147+ inters [inter ] = struct {}{}
148+ }
149+
150+ return
151+ }
0 commit comments