mirror of
https://github.com/mappu/miqt.git
synced 2024-12-22 08:58:37 +00:00
genbindings: switch to two-phase
This commit is contained in:
parent
f8a9a3f36e
commit
f6336617a0
@ -1,19 +1,29 @@
|
||||
# genbindings
|
||||
|
||||
The `genbindings` program regenerates the qt bindings.
|
||||
The `genbindings` program regenerates the Qt bindings.
|
||||
|
||||
## Archicture design
|
||||
## Architecture design
|
||||
|
||||
Bindings are generated as follows:
|
||||
Bindings are generated in two passes:
|
||||
|
||||
Pass 1
|
||||
|
||||
1. Scan input directory for header files.
|
||||
2. For each header file:
|
||||
3. Run `clang --ast-dump=json` to get a JSON ast.
|
||||
- This is somewhat slow, the results will be cached in `./cachedir` after the first run.
|
||||
- Strip all Clang AST nodes that were included from other files, to only consider the header's own definitions.
|
||||
4. Convert Clang AST to our own intermediate representation.
|
||||
5. Emit CABI cpp/h pair.
|
||||
5. Run some transformations on the intermediate representation.
|
||||
6. Cache and collect the global state of all known class names, enum names, and typedefs.
|
||||
|
||||
Pass 2
|
||||
|
||||
1. For each intermediate-representation AST:
|
||||
2. Emit "CABI" cpp/h pair.
|
||||
- The CABI is a projection of Qt into plain C. The translation unit itself is C++, but the header can be used as extern c.
|
||||
6. Emit Go binding file.
|
||||
3. Emit Go binding file.
|
||||
- The Go binding uses CGO to call into the CABI binding.
|
||||
|
||||
## Configuration
|
||||
|
||||
@ -21,5 +31,5 @@ It's tested to work on with Debian 12 / Qt 5.15 / Clang 14 / GCC 12.
|
||||
|
||||
You should check the following configuration:
|
||||
|
||||
- Input directories containing Qt headers
|
||||
- All of `exceptions.go`
|
||||
- `main.go`: Input directories containing Qt headers
|
||||
- `exceptions.go`: Check everything
|
||||
|
@ -194,6 +194,7 @@ type CppTypedef struct {
|
||||
}
|
||||
|
||||
type CppParsedHeader struct {
|
||||
Filename string
|
||||
Typedefs []CppTypedef
|
||||
Classes []CppClass
|
||||
}
|
||||
|
@ -11,6 +11,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func cacheFilePath(inputHeader string) string {
|
||||
return filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1)+".json")
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
@ -78,10 +82,12 @@ func main() {
|
||||
log.Printf("Removed %d file(s).", cleaned)
|
||||
}
|
||||
|
||||
var processHeaders []*CppParsedHeader
|
||||
|
||||
for _, inputHeader := range includeFiles {
|
||||
|
||||
// If we have a cached clang AST, use that instead
|
||||
cacheFile := filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1)+".json")
|
||||
cacheFile := cacheFilePath(inputHeader)
|
||||
astJson, err := ioutil.ReadFile(cacheFile)
|
||||
var astInner []interface{} = nil
|
||||
if err != nil {
|
||||
@ -123,11 +129,23 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
parsed.Filename = inputHeader // Stash
|
||||
|
||||
// AST transforms on our IL
|
||||
astTransformChildClasses(parsed) // must be first
|
||||
astTransformOptional(parsed)
|
||||
astTransformOverloads(parsed)
|
||||
|
||||
processHeaders = append(processHeaders, parsed)
|
||||
}
|
||||
|
||||
//
|
||||
// PASS 2
|
||||
//
|
||||
|
||||
for _, parsed := range processHeaders {
|
||||
|
||||
log.Printf("Processing %q...", parsed.Filename)
|
||||
{
|
||||
// Save the IL file for debug inspection
|
||||
jb, err := json.MarshalIndent(parsed, "", "\t")
|
||||
@ -135,7 +153,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(cacheFile+".ours.json", jb, 0644)
|
||||
err = ioutil.WriteFile(cacheFilePath(parsed.Filename)+".ours.json", jb, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -148,9 +166,9 @@ func main() {
|
||||
}
|
||||
|
||||
// Emit 3 code files from the intermediate format
|
||||
outputName := filepath.Join(*outDir, "gen_"+strings.TrimSuffix(filepath.Base(inputHeader), `.h`))
|
||||
outputName := filepath.Join(*outDir, "gen_"+strings.TrimSuffix(filepath.Base(parsed.Filename), `.h`))
|
||||
|
||||
goSrc, err := emitGo(parsed, filepath.Base(inputHeader))
|
||||
goSrc, err := emitGo(parsed, filepath.Base(parsed.Filename))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -160,7 +178,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bindingCppSrc, err := emitBindingCpp(parsed, filepath.Base(inputHeader))
|
||||
bindingCppSrc, err := emitBindingCpp(parsed, filepath.Base(parsed.Filename))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -170,7 +188,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(inputHeader))
|
||||
bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(parsed.Filename))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -182,8 +200,6 @@ func main() {
|
||||
|
||||
// Done
|
||||
|
||||
log.Printf("Processing %q completed", inputHeader)
|
||||
|
||||
}
|
||||
|
||||
log.Printf("Processing %d file(s) completed", len(includeFiles))
|
||||
|
Loading…
Reference in New Issue
Block a user