Improve clang AST parsing

To prepare genbindings for accepting arbitrary libraries from the
command line, we must retain parse types not only from the header being
processed but also its includes, to understand things like type
hierarchies etc without depending on a particular module order.

This is the first baby step that addresses clang AST filtering.

The change has some collateral benefits: the improved accuracy of the
AST parsing keeps more relevant information but at the same time reduces
the memory footprint since filtering is done streaming instead of
loading everything into memory first (ditto when writing the cache).

A consequence is that a lot more clang processes can run in parallel
without OOMing.

* parse "file" correctly to discover type provenance - using the
standard go json parser for this does not work since the  depend on
serialization order which go discards (see
https://github.com/dtolnay/clang-ast?tab=readme-ov-file#source-locations)
* stream clang output to JSON decoder and stream-write the cache to
reduce memory footprint
* with the newfound memory efficiency, bump up the number of parallel
jobs and use threads for the parsing as well
* fix missing classes such as QSysInfo using the corrected `file` source
location field
* don't try to re-run clang if it fails (OOM is unlikely anyway)
This commit is contained in:
Jacek Sieka 2025-05-24 09:41:23 +02:00
parent 5ac6083a3d
commit 6de4e762b5
29 changed files with 2295 additions and 550 deletions

View File

@ -8,172 +8,125 @@ import (
"strings"
)
type HeaderMatcher func(astNodeFilename, curFilename string) bool
func ClangMatchSameHeaderDefinitionOnly(astNodeFilename, curFilename string) bool {
return astNodeFilename == curFilename
}
type clangMatchUnderPath struct {
basePath string
}
func (c *clangMatchUnderPath) Match(astNodeFilename, curFilename string) bool {
if astNodeFilename == curFilename {
return true
}
return strings.HasPrefix(astNodeFilename, c.basePath)
}
var (
ErrTooComplex = errors.New("Type declaration is too complex to parse")
ErrNoContent = errors.New("There's no content to include")
)
// parseHeader parses a whole C++ header into our CppParsedHeader intermediate format.
func parseHeader(topLevel []interface{}, addNamePrefix string) (*CppParsedHeader, error) {
var ret CppParsedHeader
nextTopLevel:
for _, node := range topLevel {
node, ok := node.(map[string]interface{})
if !ok {
return nil, errors.New("inner[] element not an object")
func (node *AstNode) file() string {
if loc, ok := node.Fields["loc"].(map[string]interface{}); ok {
if file, ok := loc["file"].(string); ok {
return file
}
kind, ok := node["kind"].(string)
if !ok {
return nil, errors.New("node has no kind")
}
switch kind {
case "CXXRecordDecl":
// Process the inner class definition
obj, err := processClassType(node, addNamePrefix)
if err != nil {
if errors.Is(err, ErrNoContent) {
log.Printf("-> Skipping (%v)\n", err)
continue
}
// A real error (shouldn't happen)
panic(err)
if expansion, ok := loc["expansionLoc"].(map[string]interface{}); ok {
if file, ok := expansion["file"].(string); ok {
return file
}
ret.Classes = append(ret.Classes, obj)
case "StaticAssertDecl":
// ignore
case "ClassTemplateDecl",
"ClassTemplateSpecializationDecl",
"ClassTemplatePartialSpecializationDecl",
"FunctionTemplateDecl",
"BuiltinTemplateDecl", // Scintilla
"VarTemplatePartialSpecializationDecl", // e.g. Qt6 qcontainerinfo.h
"VarTemplateSpecializationDecl", // e.g. qhashfunctions.h
"TypeAliasTemplateDecl", // e.g. qendian.h
"VarTemplateDecl": // e.g. qglobal.h
// Template stuff probably can't be supported in the binding since
// we would need to link a concrete instantiation for each type in
// the CABI
// Ignore this node
case "FileScopeAsmDecl":
// ignore
case "NamespaceDecl":
// Parse everything inside the namespace with prefix, as if it is
// a whole separate file
// Then copy the parsed elements back into our own file
namespace, ok := node["name"].(string)
if !ok {
// Qt 5 has none of these
// Qt 6 has some e.g. qloggingcategory.h
// Treat it as not having existed
continue nextTopLevel
}
namespaceInner, ok := node["inner"].([]interface{})
if !ok {
// A namespace declaration with no inner content means that, for
// the rest of this whole file, we are in this namespace
// Update our own `addNamePrefix` accordingly
addNamePrefix += namespace + "::"
} else {
contents, err := parseHeader(namespaceInner, addNamePrefix+namespace+"::")
if err != nil {
panic(err)
}
ret.AddContentFrom(contents)
}
case "FunctionDecl":
// TODO
case "EnumDecl":
// Child class enum
en, err := processEnum(node, addNamePrefix)
if err != nil {
panic(fmt.Errorf("processEnum: %w", err)) // A real problem
}
// n.b. In some cases we may produce multiple "copies" of an enum
// (e.g. qcborcommon and qmetatype both define QCborSimpleType)
// Allow, but use a transform pass to avoid multiple definitions of
// it
ret.Enums = append(ret.Enums, en)
case "VarDecl":
// TODO e.g. qmath.h
// We could probably generate setter/getter for this in the CABI
case "CXXConstructorDecl":
// TODO (why is this at the top level? e.g qobject.h)
case "CXXDestructorDecl":
// ignore
case "CXXConversionDecl":
// TODO (e.g. qbytearray.h)
case "LinkageSpecDecl":
// TODO e.g. qfuturewatcher.h
// Probably can't be supported in the Go binding
case "AbiTagAttr":
// e.g. scintilla.org ScintillaEditBase
case "VisibilityAttr":
// e.g. scintilla.org ScintillaEditBase
// Don't understand why this appears at top level??
case "UsingDirectiveDecl", // qtextstream.h
"UsingDecl", // qglobal.h
"UsingShadowDecl": // global.h
// TODO e.g.
// Should be treated like a typedef
case "TypeAliasDecl", "TypedefDecl":
td, err := processTypedef(node, addNamePrefix)
if err != nil {
return nil, fmt.Errorf("processTypedef: %w", err)
}
ret.Typedefs = append(ret.Typedefs, td)
case "CXXMethodDecl":
// A C++ class method implementation directly in the header
// Skip over these
case "FullComment":
// Safe to skip
default:
return nil, fmt.Errorf("missing handling for clang ast node type %q", kind)
}
}
return ""
}
return &ret, nil // done
// parseHeader parses a whole C++ header into our CppParsedHeader intermediate format.
func parseHeader(node *AstNode, addNamePrefix string, output *CppParsedHeader, matcher HeaderMatcher) {
kind := node.Kind
switch kind {
case "TranslationUnitDecl":
for _, inner := range node.Inner {
parseHeader(inner, addNamePrefix, output, matcher)
}
case "NamespaceDecl":
if !matcher(node.file(), output.Filename) {
return
}
// Parse everything inside the namespace with prefix, as if it is
// a whole separate file
// Then copy the parsed elements back into our own file
namespace, ok := node.Fields["name"].(string)
if ok {
// Only process named namespaces
namespaceInner := node.Inner
for _, inner := range namespaceInner {
parseHeader(inner, addNamePrefix+namespace+"::", output, matcher)
}
}
case "CXXRecordDecl":
if !matcher(node.file(), output.Filename) {
return
}
// Process the inner class definition
obj, err := processClassType(node, addNamePrefix)
if err != nil {
if errors.Is(err, ErrNoContent) {
log.Printf("-> Skipping (%v)\n", err)
return
}
// A real error (shouldn't happen)
panic(err)
}
output.Classes = append(output.Classes, obj)
case "EnumDecl":
if !matcher(node.file(), output.Filename) {
return
}
// Child class enum
en, err := processEnum(node, addNamePrefix)
if err != nil {
panic(fmt.Errorf("processEnum: %w", err)) // A real problem
}
// n.b. In some cases we may produce multiple "copies" of an enum
// (e.g. qcborcommon and qmetatype both define QCborSimpleType)
// Allow, but use a transform pass to avoid multiple definitions of
// it
output.Enums = append(output.Enums, en)
case "TypeAliasDecl", "TypedefDecl":
if !matcher(node.file(), output.Filename) {
return
}
td, err := processTypedef(node, addNamePrefix)
if err != nil {
panic(fmt.Errorf("processTypedef: %w", err)) // A real problem
}
output.Typedefs = append(output.Typedefs, td)
default:
panic(fmt.Sprintf("missing handling for clang ast node type %q id %v", kind, node.Id))
}
}
// processTypedef parses a single C++ typedef into our intermediate format.
func processTypedef(node map[string]interface{}, addNamePrefix string) (CppTypedef, error) {
func processTypedef(node *AstNode, addNamePrefix string) (CppTypedef, error) {
// Must have a name
nodename, ok := node["name"].(string)
nodename, ok := node.Fields["name"].(string)
if !ok {
return CppTypedef{}, errors.New("node has no name")
}
if typ, ok := node["type"].(map[string]interface{}); ok {
if typ, ok := node.Fields["type"].(map[string]interface{}); ok {
if qualType, ok := typ["qualType"].(string); ok {
return CppTypedef{
Alias: addNamePrefix + nodename,
@ -194,12 +147,12 @@ const (
)
// processClassType parses a single C++ class definition into our intermediate format.
func processClassType(node map[string]interface{}, addNamePrefix string) (CppClass, error) {
func processClassType(node *AstNode, addNamePrefix string) (CppClass, error) {
var ret CppClass
ret.CanDelete = true
// Must have a name
nodename, ok := node["name"].(string)
nodename, ok := node.Fields["name"].(string)
if !ok {
// This can happen for some nested class definitions e.g. qbytearraymatcher.h::Data
return CppClass{}, ErrNoContent // errors.New("node has no name")
@ -223,15 +176,14 @@ func processClassType(node map[string]interface{}, addNamePrefix string) (CppCla
// Skip over forward class declarations
// This is determined in two ways:
// 1. If the class has no inner nodes
inner, ok := node["inner"].([]interface{})
if !ok {
if len(node.Inner) == 0 {
return CppClass{}, ErrNoContent
}
// 2. If this class has only one `inner` entry that's a VisibilityAttr
if len(inner) == 1 {
if node, ok := inner[0].(map[string]interface{}); ok {
if kind, ok := node["kind"].(string); ok && kind == "VisibilityAttr" {
if len(node.Inner) == 1 {
if node := node.Inner[0]; ok {
if node.Kind == "VisibilityAttr" {
return CppClass{}, ErrNoContent
}
}
@ -239,19 +191,19 @@ func processClassType(node map[string]interface{}, addNamePrefix string) (CppCla
// Check if this was 'struct' (default public) or 'class' (default private)
visibility := VsPublic
if tagUsed, ok := node["tagUsed"].(string); ok && tagUsed == "class" {
if tagUsed, ok := node.Fields["tagUsed"].(string); ok && tagUsed == "class" {
visibility = VsPrivate
}
// Check if this is an abstract class
if definitionData, ok := node["definitionData"].(map[string]interface{}); ok {
if definitionData, ok := node.Fields["definitionData"].(map[string]interface{}); ok {
if isAbstract, ok := definitionData["isAbstract"].(bool); ok && isAbstract {
ret.Abstract = true
}
}
// Check if this (publicly) inherits another class
if bases, ok := node["bases"].([]interface{}); ok {
if bases, ok := node.Fields["bases"].([]interface{}); ok {
for _, base := range bases {
base, ok := base.(map[string]interface{})
if !ok {
@ -276,21 +228,12 @@ func processClassType(node map[string]interface{}, addNamePrefix string) (CppCla
// Parse all methods
nextMethod:
for _, node := range inner {
node, ok := node.(map[string]interface{})
if !ok {
return CppClass{}, errors.New("inner[] element not an object")
}
kind, ok := node["kind"].(string)
if !ok {
panic("inner element has no kind")
}
for _, node := range node.Inner {
kind := node.Kind
switch kind {
case "AccessSpecDecl":
// Swap between visible/invisible
access, ok := node["access"].(string)
access, ok := node.Fields["access"].(string)
if !ok {
panic("AccessSpecDecl missing `access` field")
}
@ -309,7 +252,7 @@ nextMethod:
// Clang sees Q_SIGNALS/signals as being a macro for `public`
// If this AccessSpecDecl was imported from a macro, assume it's signals
isSignal = false
if loc, ok := node["loc"].(map[string]interface{}); ok {
if loc, ok := node.Fields["loc"].(map[string]interface{}); ok {
if _, ok := loc["expansionLoc"].(map[string]interface{}); ok {
isSignal = true
}
@ -359,13 +302,14 @@ nextMethod:
if err != nil {
panic(fmt.Errorf("processEnum: %w", err)) // A real problem
}
if len(en.Entries) > 0 { // e.g. qmetatype's version of QCborSimpleType (the real one is in qcborcommon)
ret.ChildEnums = append(ret.ChildEnums, en)
}
case "CXXConstructorDecl":
if isImplicit, ok := node["isImplicit"].(bool); ok && isImplicit {
if isImplicit, ok := node.Fields["isImplicit"].(bool); ok && isImplicit {
// This is an implicit ctor. Therefore the class is constructable
// even if we're currently in a `private:` block.
@ -406,7 +350,7 @@ nextMethod:
// However if this destructor is private or deleted, we should
// not bind it
if isImplicit, ok := node["isImplicit"].(bool); ok && isImplicit {
if isImplicit, ok := node.Fields["isImplicit"].(bool); ok && isImplicit {
// This is an implicit dtor. Therefore the class is deleteable
// even if we're currently in a `private:` block.
ret.CanDelete = true
@ -429,7 +373,7 @@ nextMethod:
"CXXConversionDecl": // e.g. `QColor::operator QVariant()`
// Method
methodName, ok := node["name"].(string)
methodName, ok := node.Fields["name"].(string)
if !ok {
return CppClass{}, errors.New("method has no name")
}
@ -502,13 +446,13 @@ nextMethod:
}
// isExplicitlyDeleted checks if this node is marked `= delete`.
func isExplicitlyDeleted(node map[string]interface{}) bool {
func isExplicitlyDeleted(node *AstNode) bool {
if explicitlyDeleted, ok := node["explicitlyDeleted"].(bool); ok && explicitlyDeleted {
if explicitlyDeleted, ok := node.Fields["explicitlyDeleted"].(bool); ok && explicitlyDeleted {
return true
}
if explicitlyDefaulted, ok := node["explicitlyDefaulted"].(string); ok && explicitlyDefaulted == "deleted" {
if explicitlyDefaulted, ok := node.Fields["explicitlyDefaulted"].(string); ok && explicitlyDefaulted == "deleted" {
return true
}
@ -516,19 +460,19 @@ func isExplicitlyDeleted(node map[string]interface{}) bool {
}
// processEnum parses a Clang enum into our CppEnum intermediate format.
func processEnum(node map[string]interface{}, addNamePrefix string) (CppEnum, error) {
var ret CppEnum
func processEnum(node *AstNode, addNamePrefix string) (CppEnum, error) {
var ret = CppEnum{}
// Underlying type
ret.UnderlyingType = parseSingleTypeString("int")
if nodefut, ok := node["fixedUnderlyingType"].(map[string]interface{}); ok {
if nodefut, ok := node.Fields["fixedUnderlyingType"].(map[string]interface{}); ok {
if nodequal, ok := nodefut["qualType"].(string); ok {
ret.UnderlyingType = parseSingleTypeString(nodequal)
}
}
// Name
nodename, ok := node["name"].(string)
nodename, ok := node.Fields["name"].(string)
if !ok {
// An unnamed enum is possible (e.g. qcalendar.h)
// It defines integer constants just in the current scope
@ -539,23 +483,17 @@ func processEnum(node map[string]interface{}, addNamePrefix string) (CppEnum, er
}
// Entries
inner, ok := node["inner"].([]interface{})
if !ok {
// An enum with no entries? We're done
if len(node.Inner) == 0 {
// This is either a forward declaration or an empty enum
return ret, nil
}
var lastImplicitValue int64 = -1
nextEnumEntry:
for _, entry := range inner {
entry, ok := entry.(map[string]interface{})
if !ok {
return ret, errors.New("bad inner type")
}
kind, ok := entry["kind"].(string)
if kind == "DeprecatedAttr" || kind == "FullComment" {
for _, entry := range node.Inner {
kind := entry.Kind
if kind == "DeprecatedAttr" || kind == "FullComment" || kind == "VisibilityAttr" {
continue nextEnumEntry // skip
} else if kind == "EnumConstantDecl" {
// allow
@ -566,7 +504,7 @@ nextEnumEntry:
var cee CppEnumEntry
entryname, ok := entry["name"].(string)
entryname, ok := entry.Fields["name"].(string)
if !ok {
return ret, errors.New("entry without name")
}
@ -574,7 +512,7 @@ nextEnumEntry:
cee.EntryName = entryname
// Try to find the enum value
ei1, ok := entry["inner"].([]interface{})
ei1 := entry.Inner
if !ok {
// No inner value on the enum = autoincrement
// Fall through as if a blank ei1, this will be handled
@ -586,12 +524,7 @@ nextEnumEntry:
// work for the purposes of enum constant value parsing
foundValidInner := false
for _, ei1_0 := range ei1 {
ei1_0 := ei1_0.(map[string]interface{})
ei1Kind, ok := ei1_0["kind"].(string)
if !ok {
panic("inner with no kind (1)")
}
ei1Kind := ei1_0.Kind
if ei1Kind == "FullComment" {
continue
@ -601,8 +534,7 @@ nextEnumEntry:
// Best case: .inner -> kind=ConstantExpr value=xx
// e.g. qabstractitemmodel
if ei1Kind == "ConstantExpr" {
log.Printf("Got ConstantExpr OK")
if ei1Value, ok := ei1_0["value"].(string); ok {
if ei1Value, ok := ei1_0.Fields["value"].(string); ok {
cee.EntryValue = ei1Value
goto afterParse
}
@ -611,10 +543,10 @@ nextEnumEntry:
// Best case: .inner -> kind=ImplicitCastExpr .inner -> kind=ConstantExpr value=xx
// e.g. QCalendar (when there is a int typecast)
if ei1Kind == "ImplicitCastExpr" {
if ei2, ok := ei1_0["inner"].([]interface{}); ok && len(ei2) > 0 {
ei2_0 := ei2[0].(map[string]interface{})
if ei2Kind, ok := ei2_0["kind"].(string); ok && ei2Kind == "ConstantExpr" {
if ei2Value, ok := ei2_0["value"].(string); ok {
if ei2 := ei1_0.Inner; ok && len(ei2) > 0 {
ei2_0 := ei2[0]
if ei2_0.Kind == "ConstantExpr" {
if ei2Value, ok := ei2_0.Fields["value"].(string); ok {
cee.EntryValue = ei2Value
goto afterParse
}
@ -659,9 +591,9 @@ nextEnumEntry:
}
// parseMethod parses a Clang method into our CppMethod intermediate format.
func parseMethod(node map[string]interface{}, mm *CppMethod) error {
func parseMethod(node *AstNode, mm *CppMethod) error {
if typobj, ok := node["type"].(map[string]interface{}); ok {
if typobj, ok := node.Fields["type"].(map[string]interface{}); ok {
if qualType, ok := typobj["qualType"].(string); ok {
// The qualType is the whole type of the method, including its parameter types
// If anything here is too complicated, skip the whole method
@ -671,34 +603,28 @@ func parseMethod(node map[string]interface{}, mm *CppMethod) error {
if err != nil {
return err
}
}
}
if storageClass, ok := node["storageClass"].(string); ok && storageClass == "static" {
if storageClass, ok := node.Fields["storageClass"].(string); ok && storageClass == "static" {
mm.IsStatic = true
}
if virtual, ok := node["virtual"].(bool); ok && virtual {
if virtual, ok := node.Fields["virtual"].(bool); ok && virtual {
mm.IsVirtual = true
}
if pure, ok := node["pure"].(bool); ok && pure {
if pure, ok := node.Fields["pure"].(bool); ok && pure {
mm.IsPureVirtual = true
}
if methodInner, ok := node["inner"].([]interface{}); ok {
if methodInner := node.Inner; len(methodInner) > 0 {
paramCounter := 0
for _, methodObj := range methodInner {
methodObj, ok := methodObj.(map[string]interface{})
if !ok {
return errors.New("inner[] element not an object")
}
switch methodObj["kind"] {
switch methodObj.Kind {
case "ParmVarDecl":
// Parameter variable
parmName, _ := methodObj["name"].(string) // n.b. may be unnamed
parmName, _ := methodObj.Fields["name"].(string) // n.b. may be unnamed
if parmName == "" {
// Generate a default parameter name
@ -717,7 +643,7 @@ func parseMethod(node map[string]interface{}, mm *CppMethod) error {
// If this parameter has any internal AST nodes of its
// own, assume it means it's an optional parameter
if _, ok := methodObj["inner"]; ok {
if len(methodObj.Inner) > 0 {
mm.Parameters[paramCounter].Optional = true
}
@ -732,7 +658,7 @@ func parseMethod(node map[string]interface{}, mm *CppMethod) error {
default:
// Something else inside a declaration??
log.Printf("==> NOT IMPLEMENTED CXXMethodDecl->%q\n", methodObj["kind"])
log.Printf("==> NOT IMPLEMENTED CXXMethodDecl->%q\n", methodObj.Kind)
}
}
}

341
cmd/genbindings/clangast.go Normal file
View File

@ -0,0 +1,341 @@
package main
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
func isSourceLoc(field string) bool {
// "file" (and "line" which we don't care about) takes on the last observed
// value for certain node kinds - to simplify processing, we expand it in the
// parsed AST.
// https://github.com/dtolnay/clang-ast?tab=readme-ov-file#source-locations
// https://github.com/llvm/llvm-project/blob/26d9cb17a6e655993c991b66b21d5c378256d79b/clang/lib/AST/JSONNodeDumper.cpp#L285
switch field {
case "loc", "spellingLoc", "expansionLoc", "begin", "end", "attrLoc":
return true
}
return false
}
// HexUint64 is a uint64 that marshals to/from JSON as a hex string.
type HexUint64 uint64
func (h HexUint64) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"0x%x\"", uint64(h))), nil
}
func (h *HexUint64) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
val, err := strconv.ParseUint(strings.TrimPrefix(s, "0x"), 16, 64)
if err != nil {
return err
}
*h = HexUint64(val)
return nil
}
func (h HexUint64) String() string {
return fmt.Sprintf("0x%x", uint64(h))
}
type AstNode struct {
Id HexUint64 `json:"id,omitempty"`
Kind string `json:"kind"`
Inner []*AstNode `json:"inner,omitempty"`
// TODO is there a simple way to "flatten" the fields so they appear as in
// the original AST?
Fields map[string]interface{} `json:"fields,omitempty"`
}
// User-provided function that returns true if the inner array should be parsed for a given kind.
// Return `false` to skip parsing the inner array and save some CPU cycles / memory.
type ShouldParseInner func(ctx *ParseCtx, kind string) bool
// User-provided function that returns true if the field should be added to `Fields“.
type ShouldKeepField func(ctx *ParseCtx, kind, field string, value interface{}) bool
// User-provided function for discarding inner nodes that turn out to be superfluous
// and therefore should not be added to `Inner`.
type ShouldKeepInner func(ctx *ParseCtx, parentKind string, child *AstNode) bool
type ParseCtx struct {
dec *json.Decoder
stack []*AstNode
file string // Last observed file value ("line" works the same but we don't need it)
ShouldParseInner ShouldParseInner
ShouldKeepField ShouldKeepField
ShouldKeepInner ShouldKeepInner
}
// unmarshalWithFile decodes the next value from ctx.dec similar to Decode.
// It updates ctx.file if a "file" key is encountered in a source location.
func unmarshalWithFile(ctx *ParseCtx, sourceLoc bool) (interface{}, error) {
tok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
switch v := tok.(type) {
case json.Delim:
switch v {
case '{':
// Parse object
m := make(map[string]interface{})
hasFileField := false
subLoc := false
for ctx.dec.More() {
keyTok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
key, ok := keyTok.(string)
if !ok {
return nil, fmt.Errorf("expected string key in object, got %v", keyTok)
}
val, err := unmarshalWithFile(ctx, isSourceLoc(key))
if err != nil {
return nil, err
}
m[key] = val
if sourceLoc {
if key == "file" {
ctx.file = val.(string)
hasFileField = true
} else if key == "spellingLoc" {
subLoc = true
}
}
}
// Consume closing '}'
endTok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
if endDelim, ok := endTok.(json.Delim); !ok || endDelim != '}' {
return nil, fmt.Errorf("expected '}', got %v", endTok)
}
if sourceLoc && !hasFileField && !subLoc {
// If the file is not present, use the last observed value
m["file"] = ctx.file
}
return m, nil
case '[':
// Parse array
var arr []interface{}
for ctx.dec.More() {
val, err := unmarshalWithFile(ctx, false)
if err != nil {
return nil, err
}
arr = append(arr, val)
}
// Consume closing ']'
endTok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
if endDelim, ok := endTok.(json.Delim); !ok || endDelim != ']' {
return nil, fmt.Errorf("expected ']', got %v", endTok)
}
return arr, nil
default:
return nil, fmt.Errorf("unexpected delimiter %v", v)
}
case string, float64, bool, nil:
return v, nil
default:
return nil, fmt.Errorf("unexpected token type %T", v)
}
}
// skipWithFile skips the next value from ctx.dec while updating ctx.file.
func skipWithFile(ctx *ParseCtx, sourceLoc bool) error {
tok, err := ctx.dec.Token()
if err != nil {
return err
}
switch v := tok.(type) {
case json.Delim:
switch v {
case '{':
// Parse object
for ctx.dec.More() {
keyTok, err := ctx.dec.Token()
if err != nil {
return err
}
key, ok := keyTok.(string)
if !ok {
return fmt.Errorf("expected string key in object, got %v", keyTok)
}
if sourceLoc && key == "file" {
val, err := ctx.dec.Token()
if err != nil {
return err
}
if _, ok := val.(string); !ok {
return fmt.Errorf("expected string value for file, got %v", val)
}
ctx.file = val.(string)
} else {
err = skipWithFile(ctx, isSourceLoc(key))
if err != nil {
return err
}
}
}
// Consume closing '}'
endTok, err := ctx.dec.Token()
if err != nil {
return err
}
if endDelim, ok := endTok.(json.Delim); !ok || endDelim != '}' {
return fmt.Errorf("expected '}', got %v", endTok)
}
return nil
case '[':
// Parse array
for ctx.dec.More() {
err := skipWithFile(ctx, false)
if err != nil {
return err
}
}
// Consume closing ']'
endTok, err := ctx.dec.Token()
if err != nil {
return err
}
if endDelim, ok := endTok.(json.Delim); !ok || endDelim != ']' {
return fmt.Errorf("expected ']', got %v", endTok)
}
return nil
default:
return fmt.Errorf("unexpected delimiter %v", v)
}
case string, float64, bool, nil:
return nil
default:
return fmt.Errorf("unexpected token type %T", v)
}
}
// parseClangAst parses a AstNode using the provided context and its parse function.
func parseClangAst(ctx *ParseCtx) (*AstNode, error) {
// Expect start of object
tok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
if delim, ok := tok.(json.Delim); !ok || delim != '{' {
return nil, fmt.Errorf("expected '{', got %v", tok)
}
node := &AstNode{}
for ctx.dec.More() {
fieldTok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
field, ok := fieldTok.(string)
if !ok {
return nil, fmt.Errorf("expected string for field name, got %v", fieldTok)
}
switch field {
case "id":
var idStr string
if err := ctx.dec.Decode(&idStr); err != nil {
return nil, err
}
id, err := strconv.ParseUint(strings.TrimPrefix(idStr, "0x"), 16, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse id %q as hex: %w", idStr, err)
}
node.Id = HexUint64(id)
case "kind":
var kind string
if err := ctx.dec.Decode(&kind); err != nil {
return nil, err
}
node.Kind = kind
case "inner":
if ctx.ShouldParseInner != nil && !ctx.ShouldParseInner(ctx, node.Kind) {
if err := skipWithFile(ctx, false); err != nil {
return nil, err
}
} else {
ctx.stack = append(ctx.stack, node)
// Expect start of array
tok, err := ctx.dec.Token()
if err != nil {
return nil, err
}
if delim, ok := tok.(json.Delim); !ok || delim != '[' {
return nil, fmt.Errorf("expected '[', got %v", tok)
}
var innerNodes []*AstNode
for ctx.dec.More() {
child, err := parseClangAst(ctx)
if err != nil {
return nil, err
}
// Filter inner nodes if callback is set
if ctx.ShouldKeepInner == nil || ctx.ShouldKeepInner(ctx, node.Kind, child) {
innerNodes = append(innerNodes, child)
}
}
// Expect end of array
tok, err = ctx.dec.Token()
if err != nil {
return nil, err
}
if delim, ok := tok.(json.Delim); !ok || delim != ']' {
return nil, fmt.Errorf("expected ']', got %v", tok)
}
ctx.stack = ctx.stack[:len(ctx.stack)-1]
node.Inner = innerNodes
}
default:
// Collect unknown fields, allocate map only if needed
val, err := unmarshalWithFile(ctx, isSourceLoc(field))
if err != nil {
panic(err)
}
// Filter unknown fields if callback is set
if ctx.ShouldKeepField == nil || ctx.ShouldKeepField(ctx, node.Kind, field, val) {
if node.Fields == nil {
node.Fields = make(map[string]interface{})
}
node.Fields[field] = val
}
}
}
// Expect end of object
tok, err = ctx.dec.Token()
if err != nil {
return nil, err
}
if delim, ok := tok.(json.Delim); !ok || delim != '}' {
return nil, fmt.Errorf("expected '}', got %v", tok)
}
return node, nil
}

View File

@ -1,173 +1,40 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"sync"
"time"
)
const (
ClangMaxRetries = 5
ClangRetryDelay = 3 * time.Second
)
type ClangMatcher func(astNodeFilename string) bool
func ClangMatchSameHeaderDefinitionOnly(astNodeFilename string) bool {
return astNodeFilename == ""
}
type clangMatchUnderPath struct {
basePath string
}
func (c *clangMatchUnderPath) Match(astNodeFilename string) bool {
if astNodeFilename == "" {
return true
}
return strings.HasPrefix(astNodeFilename, c.basePath)
}
//
func clangExec(ctx context.Context, clangBin, inputHeader string, cflags []string, matcher ClangMatcher) ([]interface{}, error) {
func clangExec(clangBin, inputHeader string, cflags []string) (*AstNode, error) {
clangArgs := []string{`-x`, `c++`}
clangArgs = append(clangArgs, cflags...)
clangArgs = append(clangArgs, `-Xclang`, `-ast-dump=json`, `-fsyntax-only`, inputHeader)
cmd := exec.CommandContext(ctx, clangBin, clangArgs...)
pr, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("StdoutPipe: %w", err)
}
log.Printf("clang args: %s", clangArgs)
cmd := exec.Command(clangBin, clangArgs...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("could not create stdout pipe for clang: %w", err)
}
cmd.Stderr = os.Stderr
err = cmd.Start()
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("could not start clang: %w", err)
}
ast, err := filterAst(stdout)
if err != nil {
return nil, fmt.Errorf("Start: %w", err)
return nil, fmt.Errorf("could not parse clang AST: %w", err)
}
var wg sync.WaitGroup
var inner []interface{}
var innerErr error
wg.Add(1)
go func() {
defer wg.Done()
inner, innerErr = clangStripUpToFile(pr, matcher)
}()
// Go documentation says: only call cmd.Wait once all reads from the
// StdoutPipe have completed
wg.Wait()
err = cmd.Wait()
if err != nil {
return nil, fmt.Errorf("Command: %w", err)
if err := cmd.Wait(); err != nil {
return nil, fmt.Errorf("could not wait for clang: %w", err)
}
return inner, innerErr
}
func mustClangExec(ctx context.Context, clangBin, inputHeader string, cflags []string, matcher ClangMatcher) []interface{} {
for i := 0; i < ClangMaxRetries; i++ {
astInner, err := clangExec(ctx, clangBin, inputHeader, cflags, matcher)
if err != nil {
// Log and continue with next retry
log.Printf("WARNING: Clang execution failed: %v", err)
time.Sleep(ClangRetryDelay)
log.Printf("Retrying...")
continue
}
// Success
return astInner
}
// Failed 5x
// Panic
panic("Clang failed 5x parsing file " + inputHeader)
}
// clangStripUpToFile strips all AST nodes from the clang output until we find
// one that really originated in the source file.
// This cleans out everything in the translation unit that came from an
// #included file.
// @ref https://stackoverflow.com/a/71128654
func clangStripUpToFile(stdout io.Reader, matcher ClangMatcher) ([]interface{}, error) {
var obj = map[string]interface{}{}
err := json.NewDecoder(stdout).Decode(&obj)
if err != nil {
return nil, fmt.Errorf("json.Decode: %v", err)
}
inner, ok := obj["inner"].([]interface{})
if !ok {
return nil, errors.New("no inner")
}
// This can't be done by matching the first position only, since it's possible
// that there are more #include<>s further down the file
ret := make([]interface{}, 0, len(inner))
for _, entry := range inner {
entry, ok := entry.(map[string]interface{})
if !ok {
return nil, errors.New("entry is not a map")
}
// Check where this AST node came from, if it was directly written
// in this header or if it as part of an #include
var match_filename = ""
if loc, ok := entry["loc"].(map[string]interface{}); ok {
if includedFrom, ok := loc["includedFrom"].(map[string]interface{}); ok {
if filename, ok := includedFrom["file"].(string); ok {
match_filename = filename
}
}
if match_filename == "" {
if expansionloc, ok := loc["expansionLoc"].(map[string]interface{}); ok {
if filename, ok := expansionloc["file"].(string); ok {
match_filename = filename
} else if includedFrom, ok := expansionloc["includedFrom"].(map[string]interface{}); ok {
if filename, ok := includedFrom["file"].(string); ok {
match_filename = filename
}
}
}
}
} else {
return nil, errors.New("no loc")
}
// log.Printf("# name=%v kind=%v filename=%q\n", entry["name"], entry["kind"], match_filename)
if matcher(match_filename) {
// Keep
ret = append(ret, entry)
}
// Otherwise, discard this AST node, it comes from some imported file
// that we will likely scan separately
}
return ret, nil
return ast, nil
}

View File

@ -0,0 +1,282 @@
package main
import (
"compress/gzip"
"encoding/json"
"fmt"
"io"
"log"
"os"
"strings"
)
func filteredAstPath(inputHeader string) string {
return cacheFileRoot(inputHeader) + ".filtered.json.gz"
}
func dumpStack(stack []*AstNode) string {
var ret string
for i := len(stack) - 1; i >= 0; i-- {
ret += "<" + stack[i].Kind
}
return ret
}
func allowExpressions(stack []*AstNode) bool {
// In a few exceptional cases, we parse the full expression - not because we
// really need it but because it's easier to filter it out later
for _, node := range stack {
if node.Kind == "ParmVarDecl" || node.Kind == "EnumConstantDecl" {
return true
}
}
return false
}
func parseInner(ctx *ParseCtx, kind string) bool {
// Return false for all the kinds whose inner nodes we don't care about
// at all - this is a performance optimization
switch kind {
case "TranslationUnitDecl", "NamespaceDecl":
return true
case "CXXRecordDecl", "EnumDecl", "EnumConstantDecl": // methods, fields, elements etc
return true
case "CXXConstructorDecl", "CXXMethodDecl", "CXXConversionDecl":
// Parameters, return type - skip when it's outside of a class declaration
return ctx.stack[len(ctx.stack)-1].Kind == "CXXRecordDecl"
case "CXXDestructorDecl":
return false
case "ParmVarDecl": // Parameter defaults
return true
case "TypeAliasDecl", "TypedefDecl": // Can extract from Fields
return false
case "CompoundStmt", "CXXCtorInitializer": // Bodies
return false
case "LinkageSpecDecl", "FunctionDecl", "AccessSpecDecl", "VarDecl", "FieldDecl",
"FileScopeAsmDecl", "FriendDecl", "UsingShadowDecl", "UsingDecl",
"StaticAssertDecl", "ElaboratedType", "FullComment", "ParagraphComment",
"EmptyDecl", "IndirectFieldDecl":
return false
case "ClassTemplateDecl", "TypeAliasTemplateDecl",
"ClassTemplateSpecializationDecl",
"ClassTemplatePartialSpecializationDecl", "FunctionTemplateDecl",
"VarTemplatePartialSpecializationDecl",
"VarTemplateSpecializationDecl", // e.g. qhashfunctions.h
"VarTemplateDecl", "BuiltinTemplateDecl":
return false // TODO template instantiations
case "ConstantExpr":
return true // Enum values / constants / etc
case "ImplicitCastExpr", "IntegerLiteral", "ParenExpr":
// Things we have observed in a constant expression
return true
case "ConstructorUsingShadowDecl":
// TODO using Base::Base(...)-style constructors
return false
}
if strings.HasSuffix(kind, "Attr") {
return false
}
if allowExpressions(ctx.stack) {
return true
}
log.Printf("clangfilter: unknown inner kind %s%v", kind, dumpStack(ctx.stack))
return true
}
func keepField(ctx *ParseCtx, kind, field string, val interface{}) bool {
switch field {
case "loc":
switch kind {
case "TranslationUnitDecl", "NamespaceDecl", "CXXRecordDecl", "EnumDecl",
"TypeAliasDecl", "TypedefDecl":
// only needed in parseHeader
return true
case "AccessSpecDecl":
// Signal detection
return true
}
return false
case "name", "type", "tagUsed", "definitionData", "bases", "access",
"isImplicit", "explicitlyDeleted", "explicitlyDefaulted",
"fixedUnderlyingType", "value", "storageClass", "virtual", "pure",
"file":
return true
case "range": // extended version of loc
return false
case "isReferenced", "language", "previousDecl", "originalNamespace", "isInline",
"isUsed", "mangledName", "inline", "constexpr", "parentDeclContextId",
"completeDefinition", "variadic", "target", "hasBraces", "init", "baseInit",
"nominatedNamespace", "implicit", "anyInit", "valueCategory", "castKind",
"scopedEnumTag", "argType", "opcode", "referencedDecl", "hasInClassInitializer",
"isPostfix", "canOverflow", "ctorType", "elidable", "hadMultipleCandidates",
"storageDuration", "conversionFunc", "constructionKind", "ownedTagDecl",
"isBitfield", "delegatingInit", "mutable", "boundToLValueRef",
"cleanupsHaveSideEffects", "temp", "dtor", "inherited", "isPartOfExplicitCast",
"adl", "decl", "list", "tls", "nonOdrUseReason", "zeroing":
return false
}
log.Printf("clangfilter: unknown field %v %v%v", field, kind, dumpStack(ctx.stack))
return true
}
func keepInner(ctx *ParseCtx, parentKind string, child *AstNode) bool {
// Nodes that we want to add to the inner array of their parent
switch child.Kind {
case "NamespaceDecl", "CXXRecordDecl", "EnumDecl", "TypeAliasDecl", "TypedefDecl",
"ParmVarDecl":
return true
case "StaticAssertDecl", "ClassTemplateDecl",
"ClassTemplateSpecializationDecl",
"ClassTemplatePartialSpecializationDecl",
"FunctionTemplateDecl",
"BuiltinTemplateDecl", // Scintilla
"VarTemplatePartialSpecializationDecl", // e.g. Qt6 qcontainerinfo.h
"VarTemplateSpecializationDecl", // e.g. qhashfunctions.h
"TypeAliasTemplateDecl", // e.g. qendian.h
"VarTemplateDecl", // e.g. qglobal.h
// Template stuff probably can't be supported in the binding since
// we would need to link a concrete instantiation for each type in
// the CABI
"FileScopeAsmDecl",
"FunctionDecl",
"FriendDecl", // TODO
"ElaboratedType":
return false
case "VarDecl", "FieldDecl", "IndirectFieldDecl":
// TODO e.g. qmath.h
// We could probably generate setter/getter for this in the CABI
return parentKind == "CXXRecordDecl"
case "CXXConstructorDecl", "CXXMethodDecl", "CXXConversionDecl", "CXXDestructorDecl":
return parentKind == "CXXRecordDecl"
case "LinkageSpecDecl":
// TODO e.g. qfuturewatcher.h
// Probably can't be supported in the Go binding
return false
case "OverrideAttr", "DeprecatedAttr":
return true
case "AccessSpecDecl":
return parentKind == "CXXRecordDecl"
case "UsingDirectiveDecl", // qtextstream.h
"UsingDecl", // qglobal.h
"UsingShadowDecl": // global.h
// TODO e.g.
// Should be treated like a typedef
return false
case "FullComment", "ParagraphComment", "EmptyDecl":
// Safe to skip
return false
case "CompoundStmt", "CXXCtorInitializer":
return false
case "EnumConstantDecl":
return true // Enum values
case "ConstructorUsingShadowDecl":
// TODO using Base::Base(...)-style constructors
return false
}
if strings.HasSuffix(child.Kind, "Attr") {
return false
}
if allowExpressions(ctx.stack) {
return true
}
log.Printf("clangfilter: unknown child node kind %s%v", child.Kind, dumpStack(ctx.stack))
return true
}
func filterAst(in io.Reader) (*AstNode, error) {
// Filter an AST as produced by `clang -x c++ -Xclang -ast-dump=json` to focus
// on the information needed to generate a wrapper - implementations, source
// code locations etc are broadly not used in the later stages.
var pc = ParseCtx{
dec: json.NewDecoder(in),
ShouldParseInner: parseInner,
ShouldKeepField: keepField,
ShouldKeepInner: keepInner,
}
return parseClangAst(&pc)
}
func writeCache(ast *AstNode, inputHeader string) {
// Write a compressed version of the AST to disk - the AST is generally
// highly redundant a compresses by a factor of 10-20x - the typical Qt file
// is 5-10MB and compresses to ~300-600kB
astPath := filteredAstPath(inputHeader)
compressedFile, err := os.Create(astPath)
if err != nil {
panic("could not create filtered AST cache for " + inputHeader + ": " + err.Error())
}
defer compressedFile.Close()
var gzw = gzip.NewWriter(compressedFile)
enc := json.NewEncoder(gzw)
enc.SetIndent("", " ")
err = enc.Encode(ast)
if err != nil {
panic("could not encode filtered AST cache: " + err.Error())
}
err = gzw.Close()
if err != nil {
panic("could not complete write to AST cache file: " + err.Error())
}
}
func readCache(inputHeader string) (*AstNode, error) {
compressedFile, err := os.Open(filteredAstPath(inputHeader))
if err != nil {
return nil, err
}
defer compressedFile.Close()
reader, err := gzip.NewReader(compressedFile)
if err != nil {
return nil, fmt.Errorf("could not create gzip reader for filtered AST cache: %w", err)
}
defer reader.Close()
dec := json.NewDecoder(reader)
var ast *AstNode
err = dec.Decode(&ast)
if err != nil {
return nil, fmt.Errorf("could not decode filtered AST cache: %w", err)
}
return ast, nil
}
// Get or create the filtered AST from either the given input header or a version
// When changing this function, make sure to clear the on-disk cache:
// rm -rf cachedir/*.filtered.json.gz
func getFilteredAst(inputHeader, clangBin string, cflags []string) *AstNode {
ast, err := readCache(inputHeader)
if err != nil {
if !os.IsNotExist(err) {
panic("could not open filtered AST cache for " + inputHeader + ": " + err.Error())
}
// If the file does not exist, we need to create it
// First, we need to create the AST cache
ast, err = clangExec(clangBin, inputHeader, cflags)
if err != nil {
panic("could not create AST cache for " + inputHeader + ": " + err.Error())
}
writeCache(ast, inputHeader)
}
return ast
}

View File

@ -54,14 +54,6 @@ func InsertTypedefs(qt6 bool) {
KnownTypedefs["QLibraryInfo::LibraryLocation"] = lookupResultTypedef{"qt6", CppTypedef{"QLibraryInfo::LibraryLocation", parseSingleTypeString("QLibraryInfo::LibraryPath")}}
// Enums
// QSysInfo.h is being truncated and not finding any content
KnownEnums["QSysInfo::Endian"] = lookupResultEnum{"qt6", CppEnum{
EnumName: "QSysInfo::Endian",
UnderlyingType: CppParameter{
ParameterType: "int",
},
}}
}
}
@ -98,6 +90,7 @@ func Widgets_AllowHeader(fullpath string) bool {
"q20iterator.h", // Qt 6 unstable header
"q23functional.h", // Qt 6 unstable header
"qguiapplication_platform.h", // Qt 6 - can be built for X11 but then platform-specific code fails to build on Windows
"qlogging.h", // TODO varargs
"____last____":
return false
}
@ -203,6 +196,9 @@ func AllowClass(className string) bool {
"QWebEngineQuotaRequest", // Qt 6 QWebEngine: Deprecated in Qt 6.9
"QUntypedPropertyData::InheritsQUntypedPropertyData", // qpropertyprivate.h . Hidden/undocumented class in Qt 6.4, removed in 6.7
"QFlag", // Converted to int
"QIncompatibleFlag", // Converted to int
"QAtomicInt", // Unsupported base type
"____last____":
return false
}

View File

@ -215,7 +215,6 @@ func ProcessLibraries(clangBin, outDir, extraLibsDir string) {
ClangMatchSameHeaderDefinitionOnly,
)
// Depends on QtCore/Gui/Widgets, QPrintSupport
generate(
"qt-restricted-extras/qscintilla",
@ -450,7 +449,6 @@ func ProcessLibraries(clangBin, outDir, extraLibsDir string) {
ClangMatchSameHeaderDefinitionOnly,
)
// Qt 6 PDF
generate(
"qt6/pdf",
@ -465,8 +463,6 @@ func ProcessLibraries(clangBin, outDir, extraLibsDir string) {
ClangMatchSameHeaderDefinitionOnly,
)
// Qt 6 Charts
// Depends on QtCore/Gui/Widgets
generate(

View File

@ -654,8 +654,13 @@ type CppParsedHeader struct {
func (c CppParsedHeader) Empty() bool {
// If there are only typedefs, that still counts as empty since typedefs
// are fully resolved inside genbindings, not exposed in MIQT classes
return len(c.Enums) == 0 && len(c.Classes) == 0
for _, en := range c.Enums {
if en.EnumName != "" {
// Skip the ones that triggered the astTransformRedundant
return false
}
}
return len(c.Classes) == 0
}
func (c *CppParsedHeader) AddContentFrom(other *CppParsedHeader) {

View File

@ -1,7 +1,6 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
@ -15,12 +14,16 @@ import (
)
const (
ClangSubprocessCount = 2
BaseModule = "github.com/mappu/miqt"
MaxClangSubprocessCount = 16
BaseModule = "github.com/mappu/miqt"
)
func cacheFilePath(inputHeader string) string {
return filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1)+".json")
func cacheFileRoot(inputHeader string) string {
return filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1))
}
func parsedPath(inputHeader string) string {
return cacheFileRoot(inputHeader) + ".ours.json"
}
func importPathForQtPackage(packageName string) string {
@ -93,7 +96,41 @@ func pkgConfigCflags(packageName string) string {
return string(stdout)
}
func generate(packageName string, srcDirs []string, allowHeaderFn func(string) bool, clangBin, cflagsCombined, outDir string, matcher ClangMatcher) {
func min(a, b int) int {
if a < b {
return a
}
return b
}
func parseHeaders(includeFiles []string, clangBin string, cflags []string, matcher HeaderMatcher) []*CppParsedHeader {
result := make([]*CppParsedHeader, len(includeFiles))
// Run clang / parsing in parallel but not too parallel
var wg sync.WaitGroup
ch := make(chan struct{}, min(runtime.NumCPU(), MaxClangSubprocessCount))
for i, includeFile := range includeFiles {
ch <- struct{}{}
wg.Add(1)
go func(i int, includeFile string) {
defer func() {
wg.Done()
<-ch
}()
result[i] = &CppParsedHeader{Filename: includeFile}
ast := getFilteredAst(includeFile, clangBin, cflags)
// Convert it to our intermediate format
parseHeader(ast, "", result[i], matcher)
}(i, includeFile)
}
wg.Wait()
return result
}
func generate(packageName string, srcDirs []string, allowHeaderFn func(string) bool, clangBin, cflagsCombined, outDir string, matcher HeaderMatcher) {
var includeFiles []string
for _, srcDir := range srcDirs {
@ -112,51 +149,17 @@ func generate(packageName string, srcDirs []string, allowHeaderFn func(string) b
cleanGeneratedFilesInDir(outDir)
var processHeaders []*CppParsedHeader
atr := astTransformRedundant{
preserve: make(map[string]*CppEnum),
}
//
// PASS 0 (Fill clang cache)
// PASS 1 (Parse headers and generate IL)
//
generateClangCaches(includeFiles, clangBin, cflags, matcher)
// The cache should now be fully populated.
//
// PASS 1 (clang2il)
//
for _, inputHeader := range includeFiles {
cacheFile := cacheFilePath(inputHeader)
astJson, err := os.ReadFile(cacheFile)
if err != nil {
panic("Expected cache to be created for " + inputHeader + ", but got error " + err.Error())
}
// Json decode
var astInner []interface{} = nil
err = json.Unmarshal(astJson, &astInner)
if err != nil {
panic(err)
}
if astInner == nil {
panic("Null in cache file for " + inputHeader)
}
// Convert it to our intermediate format
parsed, err := parseHeader(astInner, "")
if err != nil {
panic(err)
}
parsed.Filename = inputHeader // Stash
processHeaders := parseHeaders(includeFiles, clangBin, cflags, matcher)
for _, parsed := range processHeaders {
// AST transforms on our IL
astTransformChildClasses(parsed) // must be first
astTransformApplyQuirks(packageName, parsed) // must be before optional/overload expansion
@ -167,8 +170,6 @@ func generate(packageName string, srcDirs []string, allowHeaderFn func(string) b
// Update global state tracker (AFTER astTransformChildClasses)
addKnownTypes(packageName, parsed)
processHeaders = append(processHeaders, parsed)
}
//
@ -185,15 +186,14 @@ func generate(packageName string, srcDirs []string, allowHeaderFn func(string) b
{
// Save the IL file for debug inspection
jb, err := json.MarshalIndent(parsed, "", "\t")
if err != nil {
panic(err)
}
err = os.WriteFile(cacheFilePath(parsed.Filename)+".ours.json", jb, 0644)
file, err := os.Create(parsedPath(parsed.Filename))
if err != nil {
panic(err)
}
defer file.Close()
enc := json.NewEncoder(file)
enc.SetIndent("", "\t")
enc.Encode(parsed)
}
// Breakout if there is nothing bindable
@ -268,68 +268,6 @@ func generate(packageName string, srcDirs []string, allowHeaderFn func(string) b
log.Printf("Processing %d file(s) completed", len(includeFiles))
}
func generateClangCaches(includeFiles []string, clangBin string, cflags []string, matcher ClangMatcher) {
var clangChan = make(chan string)
var clangWg sync.WaitGroup
ctx := context.Background()
for i := 0; i < ClangSubprocessCount; i++ {
clangWg.Add(1)
go func() {
defer clangWg.Done()
log.Printf("Clang worker: starting")
for {
inputHeader, ok := <-clangChan
if !ok {
return // Done
}
log.Printf("Clang worker got message for file %q", inputHeader)
// Parse the file
// This seems to intermittently fail, so allow retrying
astInner := mustClangExec(ctx, clangBin, inputHeader, cflags, matcher)
// Write to cache
jb, err := json.MarshalIndent(astInner, "", "\t")
if err != nil {
panic(err)
}
err = os.WriteFile(cacheFilePath(inputHeader), jb, 0644)
if err != nil {
panic(err)
}
astInner = nil
jb = nil
runtime.GC()
}
log.Printf("Clang worker: exiting")
}()
}
for _, inputHeader := range includeFiles {
// Check if there is a matching cache hit
cacheFile := cacheFilePath(inputHeader)
if _, err := os.Stat(cacheFile); err != nil && os.IsNotExist(err) {
// Nonexistent cache file, regenerate from clang
log.Printf("No AST cache for file %q, running clang...", filepath.Base(inputHeader))
clangChan <- inputHeader
}
}
// Done with all clang workers
close(clangChan)
clangWg.Wait()
}
func main() {
// data/time flags make logs hard to compare across runs
log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))

View File

@ -26,6 +26,7 @@ func (a *astTransformRedundant) Process(parsed *CppParsedHeader) {
// Remove from second matched header
// This is difficult to manipulate while preserving pointers, so only
// wipe out the name and use that as a signal later on
// TODO This breaks anonymous enums (such as QTypeInfo)
parsed.Enums[i].EnumName = ""
}
}

View File

@ -15,14 +15,6 @@ import (
"unsafe"
)
type std__pointer_safety int
const (
Std__relaxed std__pointer_safety = 0
Std__preferred std__pointer_safety = 1
Std__strict std__pointer_safety = 2
)
type Scintilla__Internal__Edge int
const (
@ -1662,12 +1654,6 @@ const (
Scintilla__Message__SetBidirectional Scintilla__Message = 2709
)
type std__nullopt_t___Construct int
const (
Std__nullopt_t___Token std__nullopt_t___Construct = 0
)
type Scintilla__Internal__Surface__Ends int
const (

11
qt/gen_qglobalstatic.cpp Normal file
View File

@ -0,0 +1,11 @@
#include <qglobalstatic.h>
#include "gen_qglobalstatic.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif

18
qt/gen_qglobalstatic.go Normal file
View File

@ -0,0 +1,18 @@
package qt
/*
#include "gen_qglobalstatic.h"
#include <stdlib.h>
*/
import "C"
type QtGlobalStatic__GuardValues int
const (
QtGlobalStatic__Destroyed QtGlobalStatic__GuardValues = -2
QtGlobalStatic__Initialized QtGlobalStatic__GuardValues = -1
QtGlobalStatic__Uninitialized QtGlobalStatic__GuardValues = 0
QtGlobalStatic__Initializing QtGlobalStatic__GuardValues = 1
)

25
qt/gen_qglobalstatic.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#ifndef MIQT_QT_GEN_QGLOBALSTATIC_H
#define MIQT_QT_GEN_QGLOBALSTATIC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "../libmiqt/libmiqt.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
#else
#endif
#ifdef __cplusplus
} /* extern C */
#endif
#endif

224
qt/gen_qstringlist.cpp Normal file
View File

@ -0,0 +1,224 @@
#include <QList>
#include <QRegExp>
#include <QRegularExpression>
#include <QString>
#include <QByteArray>
#include <cstring>
#include <QStringList>
#include <qstringlist.h>
#include "gen_qstringlist.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif
QStringList* QStringList_new() {
return new QStringList();
}
QStringList* QStringList_new2(struct miqt_string i) {
QString i_QString = QString::fromUtf8(i.data, i.len);
return new QStringList(i_QString);
}
QStringList* QStringList_new3(struct miqt_array /* of struct miqt_string */ l) {
QList<QString> l_QList;
l_QList.reserve(l.len);
struct miqt_string* l_arr = static_cast<struct miqt_string*>(l.data);
for(size_t i = 0; i < l.len; ++i) {
QString l_arr_i_QString = QString::fromUtf8(l_arr[i].data, l_arr[i].len);
l_QList.push_back(l_arr_i_QString);
}
return new QStringList(l_QList);
}
void QStringList_operatorAssign(QStringList* self, struct miqt_array /* of struct miqt_string */ other) {
QList<QString> other_QList;
other_QList.reserve(other.len);
struct miqt_string* other_arr = static_cast<struct miqt_string*>(other.data);
for(size_t i = 0; i < other.len; ++i) {
QString other_arr_i_QString = QString::fromUtf8(other_arr[i].data, other_arr[i].len);
other_QList.push_back(other_arr_i_QString);
}
self->operator=(other_QList);
}
bool QStringList_contains(const QStringList* self, struct miqt_string str) {
QString str_QString = QString::fromUtf8(str.data, str.len);
return self->contains(str_QString);
}
struct miqt_array /* of struct miqt_string */ QStringList_operatorPlus(const QStringList* self, struct miqt_array /* of struct miqt_string */ other) {
QStringList other_QList;
other_QList.reserve(other.len);
struct miqt_string* other_arr = static_cast<struct miqt_string*>(other.data);
for(size_t i = 0; i < other.len; ++i) {
QString other_arr_i_QString = QString::fromUtf8(other_arr[i].data, other_arr[i].len);
other_QList.push_back(other_arr_i_QString);
}
QStringList _ret = self->operator+(other_QList);
// Convert QList<> from C++ memory to manually-managed C memory
struct miqt_string* _arr = static_cast<struct miqt_string*>(malloc(sizeof(struct miqt_string) * _ret.length()));
for (size_t i = 0, e = _ret.length(); i < e; ++i) {
QString _lv_ret = _ret[i];
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _lv_b = _lv_ret.toUtf8();
struct miqt_string _lv_ms;
_lv_ms.len = _lv_b.length();
_lv_ms.data = static_cast<char*>(malloc(_lv_ms.len));
memcpy(_lv_ms.data, _lv_b.data(), _lv_ms.len);
_arr[i] = _lv_ms;
}
struct miqt_array _out;
_out.len = _ret.length();
_out.data = static_cast<void*>(_arr);
return _out;
}
struct miqt_array /* of struct miqt_string */ QStringList_operatorShiftLeft(QStringList* self, struct miqt_string str) {
QString str_QString = QString::fromUtf8(str.data, str.len);
QStringList& _ret = self->operator<<(str_QString);
// Convert QList<> from C++ memory to manually-managed C memory
struct miqt_string* _arr = static_cast<struct miqt_string*>(malloc(sizeof(struct miqt_string) * _ret.length()));
for (size_t i = 0, e = _ret.length(); i < e; ++i) {
QString _lv_ret = _ret[i];
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _lv_b = _lv_ret.toUtf8();
struct miqt_string _lv_ms;
_lv_ms.len = _lv_b.length();
_lv_ms.data = static_cast<char*>(malloc(_lv_ms.len));
memcpy(_lv_ms.data, _lv_b.data(), _lv_ms.len);
_arr[i] = _lv_ms;
}
struct miqt_array _out;
_out.len = _ret.length();
_out.data = static_cast<void*>(_arr);
return _out;
}
struct miqt_array /* of struct miqt_string */ QStringList_operatorShiftLeftWithQStringList(QStringList* self, struct miqt_array /* of struct miqt_string */ l) {
QStringList l_QList;
l_QList.reserve(l.len);
struct miqt_string* l_arr = static_cast<struct miqt_string*>(l.data);
for(size_t i = 0; i < l.len; ++i) {
QString l_arr_i_QString = QString::fromUtf8(l_arr[i].data, l_arr[i].len);
l_QList.push_back(l_arr_i_QString);
}
QStringList& _ret = self->operator<<(l_QList);
// Convert QList<> from C++ memory to manually-managed C memory
struct miqt_string* _arr = static_cast<struct miqt_string*>(malloc(sizeof(struct miqt_string) * _ret.length()));
for (size_t i = 0, e = _ret.length(); i < e; ++i) {
QString _lv_ret = _ret[i];
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _lv_b = _lv_ret.toUtf8();
struct miqt_string _lv_ms;
_lv_ms.len = _lv_b.length();
_lv_ms.data = static_cast<char*>(malloc(_lv_ms.len));
memcpy(_lv_ms.data, _lv_b.data(), _lv_ms.len);
_arr[i] = _lv_ms;
}
struct miqt_array _out;
_out.len = _ret.length();
_out.data = static_cast<void*>(_arr);
return _out;
}
struct miqt_array /* of struct miqt_string */ QStringList_operatorShiftLeftWithQListLesserQStringGreater(QStringList* self, struct miqt_array /* of struct miqt_string */ l) {
QList<QString> l_QList;
l_QList.reserve(l.len);
struct miqt_string* l_arr = static_cast<struct miqt_string*>(l.data);
for(size_t i = 0; i < l.len; ++i) {
QString l_arr_i_QString = QString::fromUtf8(l_arr[i].data, l_arr[i].len);
l_QList.push_back(l_arr_i_QString);
}
QStringList& _ret = self->operator<<(l_QList);
// Convert QList<> from C++ memory to manually-managed C memory
struct miqt_string* _arr = static_cast<struct miqt_string*>(malloc(sizeof(struct miqt_string) * _ret.length()));
for (size_t i = 0, e = _ret.length(); i < e; ++i) {
QString _lv_ret = _ret[i];
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _lv_b = _lv_ret.toUtf8();
struct miqt_string _lv_ms;
_lv_ms.len = _lv_b.length();
_lv_ms.data = static_cast<char*>(malloc(_lv_ms.len));
memcpy(_lv_ms.data, _lv_b.data(), _lv_ms.len);
_arr[i] = _lv_ms;
}
struct miqt_array _out;
_out.len = _ret.length();
_out.data = static_cast<void*>(_arr);
return _out;
}
int QStringList_indexOfWithRx(const QStringList* self, QRegExp* rx) {
return self->indexOf(*rx);
}
int QStringList_lastIndexOfWithRx(const QStringList* self, QRegExp* rx) {
return self->lastIndexOf(*rx);
}
int QStringList_indexOf2(const QStringList* self, QRegExp* rx) {
return self->indexOf(*rx);
}
int QStringList_lastIndexOf2(const QStringList* self, QRegExp* rx) {
return self->lastIndexOf(*rx);
}
int QStringList_indexOfWithRe(const QStringList* self, QRegularExpression* re) {
return self->indexOf(*re);
}
int QStringList_lastIndexOfWithRe(const QStringList* self, QRegularExpression* re) {
return self->lastIndexOf(*re);
}
void QStringList_operatorAssignWithQStringList(QStringList* self, struct miqt_array /* of struct miqt_string */ param1) {
QStringList param1_QList;
param1_QList.reserve(param1.len);
struct miqt_string* param1_arr = static_cast<struct miqt_string*>(param1.data);
for(size_t i = 0; i < param1.len; ++i) {
QString param1_arr_i_QString = QString::fromUtf8(param1_arr[i].data, param1_arr[i].len);
param1_QList.push_back(param1_arr_i_QString);
}
self->operator=(param1_QList);
}
bool QStringList_contains3(const QStringList* self, struct miqt_string str, int cs) {
QString str_QString = QString::fromUtf8(str.data, str.len);
return self->contains(str_QString, static_cast<Qt::CaseSensitivity>(cs));
}
int QStringList_indexOf5(const QStringList* self, QRegExp* rx, int from) {
return self->indexOf(*rx, static_cast<int>(from));
}
int QStringList_lastIndexOf5(const QStringList* self, QRegExp* rx, int from) {
return self->lastIndexOf(*rx, static_cast<int>(from));
}
int QStringList_indexOf6(const QStringList* self, QRegExp* rx, int from) {
return self->indexOf(*rx, static_cast<int>(from));
}
int QStringList_lastIndexOf6(const QStringList* self, QRegExp* rx, int from) {
return self->lastIndexOf(*rx, static_cast<int>(from));
}
int QStringList_indexOf7(const QStringList* self, QRegularExpression* re, int from) {
return self->indexOf(*re, static_cast<int>(from));
}
int QStringList_lastIndexOf7(const QStringList* self, QRegularExpression* re, int from) {
return self->lastIndexOf(*re, static_cast<int>(from));
}
void QStringList_delete(QStringList* self) {
delete self;
}

272
qt/gen_qstringlist.go Normal file
View File

@ -0,0 +1,272 @@
package qt
/*
#include "gen_qstringlist.h"
#include <stdlib.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
type QStringList struct {
h *C.QStringList
/* Also inherits unprojectable QList<QString> */
}
func (this *QStringList) cPointer() *C.QStringList {
if this == nil {
return nil
}
return this.h
}
func (this *QStringList) UnsafePointer() unsafe.Pointer {
if this == nil {
return nil
}
return unsafe.Pointer(this.h)
}
// newQStringList constructs the type using only CGO pointers.
func newQStringList(h *C.QStringList) *QStringList {
if h == nil {
return nil
}
return &QStringList{h: h}
}
// UnsafeNewQStringList constructs the type using only unsafe pointers.
func UnsafeNewQStringList(h unsafe.Pointer) *QStringList {
return newQStringList((*C.QStringList)(h))
}
// NewQStringList constructs a new QStringList object.
func NewQStringList() *QStringList {
return newQStringList(C.QStringList_new())
}
// NewQStringList2 constructs a new QStringList object.
func NewQStringList2(i string) *QStringList {
i_ms := C.struct_miqt_string{}
i_ms.data = C.CString(i)
i_ms.len = C.size_t(len(i))
defer C.free(unsafe.Pointer(i_ms.data))
return newQStringList(C.QStringList_new2(i_ms))
}
// NewQStringList3 constructs a new QStringList object.
func NewQStringList3(l []string) *QStringList {
l_CArray := (*[0xffff]C.struct_miqt_string)(C.malloc(C.size_t(int(unsafe.Sizeof(C.struct_miqt_string{})) * len(l))))
defer C.free(unsafe.Pointer(l_CArray))
for i := range l {
l_i_ms := C.struct_miqt_string{}
l_i_ms.data = C.CString(l[i])
l_i_ms.len = C.size_t(len(l[i]))
defer C.free(unsafe.Pointer(l_i_ms.data))
l_CArray[i] = l_i_ms
}
l_ma := C.struct_miqt_array{len: C.size_t(len(l)), data: unsafe.Pointer(l_CArray)}
return newQStringList(C.QStringList_new3(l_ma))
}
func (this *QStringList) OperatorAssign(other []string) {
other_CArray := (*[0xffff]C.struct_miqt_string)(C.malloc(C.size_t(int(unsafe.Sizeof(C.struct_miqt_string{})) * len(other))))
defer C.free(unsafe.Pointer(other_CArray))
for i := range other {
other_i_ms := C.struct_miqt_string{}
other_i_ms.data = C.CString(other[i])
other_i_ms.len = C.size_t(len(other[i]))
defer C.free(unsafe.Pointer(other_i_ms.data))
other_CArray[i] = other_i_ms
}
other_ma := C.struct_miqt_array{len: C.size_t(len(other)), data: unsafe.Pointer(other_CArray)}
C.QStringList_operatorAssign(this.h, other_ma)
}
func (this *QStringList) Contains(str string) bool {
str_ms := C.struct_miqt_string{}
str_ms.data = C.CString(str)
str_ms.len = C.size_t(len(str))
defer C.free(unsafe.Pointer(str_ms.data))
return (bool)(C.QStringList_contains(this.h, str_ms))
}
func (this *QStringList) OperatorPlus(other []string) []string {
other_CArray := (*[0xffff]C.struct_miqt_string)(C.malloc(C.size_t(int(unsafe.Sizeof(C.struct_miqt_string{})) * len(other))))
defer C.free(unsafe.Pointer(other_CArray))
for i := range other {
other_i_ms := C.struct_miqt_string{}
other_i_ms.data = C.CString(other[i])
other_i_ms.len = C.size_t(len(other[i]))
defer C.free(unsafe.Pointer(other_i_ms.data))
other_CArray[i] = other_i_ms
}
other_ma := C.struct_miqt_array{len: C.size_t(len(other)), data: unsafe.Pointer(other_CArray)}
var _ma C.struct_miqt_array = C.QStringList_operatorPlus(this.h, other_ma)
_ret := make([]string, int(_ma.len))
_outCast := (*[0xffff]C.struct_miqt_string)(unsafe.Pointer(_ma.data)) // hey ya
for i := 0; i < int(_ma.len); i++ {
var _lv_ms C.struct_miqt_string = _outCast[i]
_lv_ret := C.GoStringN(_lv_ms.data, C.int(int64(_lv_ms.len)))
C.free(unsafe.Pointer(_lv_ms.data))
_ret[i] = _lv_ret
}
return _ret
}
func (this *QStringList) OperatorShiftLeft(str string) []string {
str_ms := C.struct_miqt_string{}
str_ms.data = C.CString(str)
str_ms.len = C.size_t(len(str))
defer C.free(unsafe.Pointer(str_ms.data))
var _ma C.struct_miqt_array = C.QStringList_operatorShiftLeft(this.h, str_ms)
_ret := make([]string, int(_ma.len))
_outCast := (*[0xffff]C.struct_miqt_string)(unsafe.Pointer(_ma.data)) // hey ya
for i := 0; i < int(_ma.len); i++ {
var _lv_ms C.struct_miqt_string = _outCast[i]
_lv_ret := C.GoStringN(_lv_ms.data, C.int(int64(_lv_ms.len)))
C.free(unsafe.Pointer(_lv_ms.data))
_ret[i] = _lv_ret
}
return _ret
}
func (this *QStringList) OperatorShiftLeftWithQStringList(l []string) []string {
l_CArray := (*[0xffff]C.struct_miqt_string)(C.malloc(C.size_t(int(unsafe.Sizeof(C.struct_miqt_string{})) * len(l))))
defer C.free(unsafe.Pointer(l_CArray))
for i := range l {
l_i_ms := C.struct_miqt_string{}
l_i_ms.data = C.CString(l[i])
l_i_ms.len = C.size_t(len(l[i]))
defer C.free(unsafe.Pointer(l_i_ms.data))
l_CArray[i] = l_i_ms
}
l_ma := C.struct_miqt_array{len: C.size_t(len(l)), data: unsafe.Pointer(l_CArray)}
var _ma C.struct_miqt_array = C.QStringList_operatorShiftLeftWithQStringList(this.h, l_ma)
_ret := make([]string, int(_ma.len))
_outCast := (*[0xffff]C.struct_miqt_string)(unsafe.Pointer(_ma.data)) // hey ya
for i := 0; i < int(_ma.len); i++ {
var _lv_ms C.struct_miqt_string = _outCast[i]
_lv_ret := C.GoStringN(_lv_ms.data, C.int(int64(_lv_ms.len)))
C.free(unsafe.Pointer(_lv_ms.data))
_ret[i] = _lv_ret
}
return _ret
}
func (this *QStringList) OperatorShiftLeftWithQListLesserQStringGreater(l []string) []string {
l_CArray := (*[0xffff]C.struct_miqt_string)(C.malloc(C.size_t(int(unsafe.Sizeof(C.struct_miqt_string{})) * len(l))))
defer C.free(unsafe.Pointer(l_CArray))
for i := range l {
l_i_ms := C.struct_miqt_string{}
l_i_ms.data = C.CString(l[i])
l_i_ms.len = C.size_t(len(l[i]))
defer C.free(unsafe.Pointer(l_i_ms.data))
l_CArray[i] = l_i_ms
}
l_ma := C.struct_miqt_array{len: C.size_t(len(l)), data: unsafe.Pointer(l_CArray)}
var _ma C.struct_miqt_array = C.QStringList_operatorShiftLeftWithQListLesserQStringGreater(this.h, l_ma)
_ret := make([]string, int(_ma.len))
_outCast := (*[0xffff]C.struct_miqt_string)(unsafe.Pointer(_ma.data)) // hey ya
for i := 0; i < int(_ma.len); i++ {
var _lv_ms C.struct_miqt_string = _outCast[i]
_lv_ret := C.GoStringN(_lv_ms.data, C.int(int64(_lv_ms.len)))
C.free(unsafe.Pointer(_lv_ms.data))
_ret[i] = _lv_ret
}
return _ret
}
func (this *QStringList) IndexOfWithRx(rx *QRegExp) int {
return (int)(C.QStringList_indexOfWithRx(this.h, rx.cPointer()))
}
func (this *QStringList) LastIndexOfWithRx(rx *QRegExp) int {
return (int)(C.QStringList_lastIndexOfWithRx(this.h, rx.cPointer()))
}
func (this *QStringList) IndexOf2(rx *QRegExp) int {
return (int)(C.QStringList_indexOf2(this.h, rx.cPointer()))
}
func (this *QStringList) LastIndexOf2(rx *QRegExp) int {
return (int)(C.QStringList_lastIndexOf2(this.h, rx.cPointer()))
}
func (this *QStringList) IndexOfWithRe(re *QRegularExpression) int {
return (int)(C.QStringList_indexOfWithRe(this.h, re.cPointer()))
}
func (this *QStringList) LastIndexOfWithRe(re *QRegularExpression) int {
return (int)(C.QStringList_lastIndexOfWithRe(this.h, re.cPointer()))
}
func (this *QStringList) OperatorAssignWithQStringList(param1 []string) {
param1_CArray := (*[0xffff]C.struct_miqt_string)(C.malloc(C.size_t(int(unsafe.Sizeof(C.struct_miqt_string{})) * len(param1))))
defer C.free(unsafe.Pointer(param1_CArray))
for i := range param1 {
param1_i_ms := C.struct_miqt_string{}
param1_i_ms.data = C.CString(param1[i])
param1_i_ms.len = C.size_t(len(param1[i]))
defer C.free(unsafe.Pointer(param1_i_ms.data))
param1_CArray[i] = param1_i_ms
}
param1_ma := C.struct_miqt_array{len: C.size_t(len(param1)), data: unsafe.Pointer(param1_CArray)}
C.QStringList_operatorAssignWithQStringList(this.h, param1_ma)
}
func (this *QStringList) Contains3(str string, cs CaseSensitivity) bool {
str_ms := C.struct_miqt_string{}
str_ms.data = C.CString(str)
str_ms.len = C.size_t(len(str))
defer C.free(unsafe.Pointer(str_ms.data))
return (bool)(C.QStringList_contains3(this.h, str_ms, (C.int)(cs)))
}
func (this *QStringList) IndexOf5(rx *QRegExp, from int) int {
return (int)(C.QStringList_indexOf5(this.h, rx.cPointer(), (C.int)(from)))
}
func (this *QStringList) LastIndexOf5(rx *QRegExp, from int) int {
return (int)(C.QStringList_lastIndexOf5(this.h, rx.cPointer(), (C.int)(from)))
}
func (this *QStringList) IndexOf6(rx *QRegExp, from int) int {
return (int)(C.QStringList_indexOf6(this.h, rx.cPointer(), (C.int)(from)))
}
func (this *QStringList) LastIndexOf6(rx *QRegExp, from int) int {
return (int)(C.QStringList_lastIndexOf6(this.h, rx.cPointer(), (C.int)(from)))
}
func (this *QStringList) IndexOf7(re *QRegularExpression, from int) int {
return (int)(C.QStringList_indexOf7(this.h, re.cPointer(), (C.int)(from)))
}
func (this *QStringList) LastIndexOf7(re *QRegularExpression, from int) int {
return (int)(C.QStringList_lastIndexOf7(this.h, re.cPointer(), (C.int)(from)))
}
// Delete this object from C++ memory.
func (this *QStringList) Delete() {
C.QStringList_delete(this.h)
}
// GoGC adds a Go Finalizer to this pointer, so that it will be deleted
// from C++ memory once it is unreachable from Go memory.
func (this *QStringList) GoGC() {
runtime.SetFinalizer(this, func(this *QStringList) {
this.Delete()
runtime.KeepAlive(this.h)
})
}

56
qt/gen_qstringlist.h Normal file
View File

@ -0,0 +1,56 @@
#pragma once
#ifndef MIQT_QT_GEN_QSTRINGLIST_H
#define MIQT_QT_GEN_QSTRINGLIST_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "../libmiqt/libmiqt.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
class QRegExp;
class QRegularExpression;
class QStringList;
#else
typedef struct QRegExp QRegExp;
typedef struct QRegularExpression QRegularExpression;
typedef struct QStringList QStringList;
#endif
QStringList* QStringList_new();
QStringList* QStringList_new2(struct miqt_string i);
QStringList* QStringList_new3(struct miqt_array /* of struct miqt_string */ l);
void QStringList_operatorAssign(QStringList* self, struct miqt_array /* of struct miqt_string */ other);
bool QStringList_contains(const QStringList* self, struct miqt_string str);
struct miqt_array /* of struct miqt_string */ QStringList_operatorPlus(const QStringList* self, struct miqt_array /* of struct miqt_string */ other);
struct miqt_array /* of struct miqt_string */ QStringList_operatorShiftLeft(QStringList* self, struct miqt_string str);
struct miqt_array /* of struct miqt_string */ QStringList_operatorShiftLeftWithQStringList(QStringList* self, struct miqt_array /* of struct miqt_string */ l);
struct miqt_array /* of struct miqt_string */ QStringList_operatorShiftLeftWithQListLesserQStringGreater(QStringList* self, struct miqt_array /* of struct miqt_string */ l);
int QStringList_indexOfWithRx(const QStringList* self, QRegExp* rx);
int QStringList_lastIndexOfWithRx(const QStringList* self, QRegExp* rx);
int QStringList_indexOf2(const QStringList* self, QRegExp* rx);
int QStringList_lastIndexOf2(const QStringList* self, QRegExp* rx);
int QStringList_indexOfWithRe(const QStringList* self, QRegularExpression* re);
int QStringList_lastIndexOfWithRe(const QStringList* self, QRegularExpression* re);
void QStringList_operatorAssignWithQStringList(QStringList* self, struct miqt_array /* of struct miqt_string */ param1);
bool QStringList_contains3(const QStringList* self, struct miqt_string str, int cs);
int QStringList_indexOf5(const QStringList* self, QRegExp* rx, int from);
int QStringList_lastIndexOf5(const QStringList* self, QRegExp* rx, int from);
int QStringList_indexOf6(const QStringList* self, QRegExp* rx, int from);
int QStringList_lastIndexOf6(const QStringList* self, QRegExp* rx, int from);
int QStringList_indexOf7(const QStringList* self, QRegularExpression* re, int from);
int QStringList_lastIndexOf7(const QStringList* self, QRegularExpression* re, int from);
void QStringList_delete(QStringList* self);
#ifdef __cplusplus
} /* extern C */
#endif
#endif

147
qt/gen_qsysinfo.cpp Normal file
View File

@ -0,0 +1,147 @@
#include <QByteArray>
#include <QString>
#include <QByteArray>
#include <cstring>
#include <QSysInfo>
#include <qsysinfo.h>
#include "gen_qsysinfo.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif
int QSysInfo_windowsVersion() {
QSysInfo::WinVersion _ret = QSysInfo::windowsVersion();
return static_cast<int>(_ret);
}
int QSysInfo_macVersion() {
QSysInfo::MacVersion _ret = QSysInfo::macVersion();
return static_cast<int>(_ret);
}
struct miqt_string QSysInfo_buildCpuArchitecture() {
QString _ret = QSysInfo::buildCpuArchitecture();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_currentCpuArchitecture() {
QString _ret = QSysInfo::currentCpuArchitecture();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_buildAbi() {
QString _ret = QSysInfo::buildAbi();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_kernelType() {
QString _ret = QSysInfo::kernelType();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_kernelVersion() {
QString _ret = QSysInfo::kernelVersion();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_productType() {
QString _ret = QSysInfo::productType();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_productVersion() {
QString _ret = QSysInfo::productVersion();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_prettyProductName() {
QString _ret = QSysInfo::prettyProductName();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_machineHostName() {
QString _ret = QSysInfo::machineHostName();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_machineUniqueId() {
QByteArray _qb = QSysInfo::machineUniqueId();
struct miqt_string _ms;
_ms.len = _qb.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _qb.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_bootUniqueId() {
QByteArray _qb = QSysInfo::bootUniqueId();
struct miqt_string _ms;
_ms.len = _qb.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _qb.data(), _ms.len);
return _ms;
}
void QSysInfo_delete(QSysInfo* self) {
delete self;
}

256
qt/gen_qsysinfo.go Normal file
View File

@ -0,0 +1,256 @@
package qt
/*
#include "gen_qsysinfo.h"
#include <stdlib.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
type QSysInfo__Sizes int
const (
QSysInfo__WordSize QSysInfo__Sizes = 64
)
type QSysInfo__Endian int
const (
QSysInfo__BigEndian QSysInfo__Endian = 0
QSysInfo__LittleEndian QSysInfo__Endian = 1
QSysInfo__ByteOrder QSysInfo__Endian = 1
)
type QSysInfo__WinVersion int
const (
QSysInfo__WV_None QSysInfo__WinVersion = 0
QSysInfo__WV_32s QSysInfo__WinVersion = 1
QSysInfo__WV_95 QSysInfo__WinVersion = 2
QSysInfo__WV_98 QSysInfo__WinVersion = 3
QSysInfo__WV_Me QSysInfo__WinVersion = 4
QSysInfo__WV_DOS_based QSysInfo__WinVersion = 15
QSysInfo__WV_NT QSysInfo__WinVersion = 16
QSysInfo__WV_2000 QSysInfo__WinVersion = 32
QSysInfo__WV_XP QSysInfo__WinVersion = 48
QSysInfo__WV_2003 QSysInfo__WinVersion = 64
QSysInfo__WV_VISTA QSysInfo__WinVersion = 128
QSysInfo__WV_WINDOWS7 QSysInfo__WinVersion = 144
QSysInfo__WV_WINDOWS8 QSysInfo__WinVersion = 160
QSysInfo__WV_WINDOWS8_1 QSysInfo__WinVersion = 176
QSysInfo__WV_WINDOWS10 QSysInfo__WinVersion = 192
QSysInfo__WV_NT_based QSysInfo__WinVersion = 240
QSysInfo__WV_4_0 QSysInfo__WinVersion = 16
QSysInfo__WV_5_0 QSysInfo__WinVersion = 32
QSysInfo__WV_5_1 QSysInfo__WinVersion = 48
QSysInfo__WV_5_2 QSysInfo__WinVersion = 64
QSysInfo__WV_6_0 QSysInfo__WinVersion = 128
QSysInfo__WV_6_1 QSysInfo__WinVersion = 144
QSysInfo__WV_6_2 QSysInfo__WinVersion = 160
QSysInfo__WV_6_3 QSysInfo__WinVersion = 176
QSysInfo__WV_10_0 QSysInfo__WinVersion = 192
QSysInfo__WV_CE QSysInfo__WinVersion = 256
QSysInfo__WV_CENET QSysInfo__WinVersion = 512
QSysInfo__WV_CE_5 QSysInfo__WinVersion = 768
QSysInfo__WV_CE_6 QSysInfo__WinVersion = 1024
QSysInfo__WV_CE_based QSysInfo__WinVersion = 3840
)
type QSysInfo__MacVersion int
const (
QSysInfo__MV_None QSysInfo__MacVersion = 65535
QSysInfo__MV_Unknown QSysInfo__MacVersion = 0
QSysInfo__MV_9 QSysInfo__MacVersion = 1
QSysInfo__MV_10_0 QSysInfo__MacVersion = 2
QSysInfo__MV_10_1 QSysInfo__MacVersion = 3
QSysInfo__MV_10_2 QSysInfo__MacVersion = 4
QSysInfo__MV_10_3 QSysInfo__MacVersion = 5
QSysInfo__MV_10_4 QSysInfo__MacVersion = 6
QSysInfo__MV_10_5 QSysInfo__MacVersion = 7
QSysInfo__MV_10_6 QSysInfo__MacVersion = 8
QSysInfo__MV_10_7 QSysInfo__MacVersion = 9
QSysInfo__MV_10_8 QSysInfo__MacVersion = 10
QSysInfo__MV_10_9 QSysInfo__MacVersion = 11
QSysInfo__MV_10_10 QSysInfo__MacVersion = 12
QSysInfo__MV_10_11 QSysInfo__MacVersion = 13
QSysInfo__MV_10_12 QSysInfo__MacVersion = 14
QSysInfo__MV_CHEETAH QSysInfo__MacVersion = 2
QSysInfo__MV_PUMA QSysInfo__MacVersion = 3
QSysInfo__MV_JAGUAR QSysInfo__MacVersion = 4
QSysInfo__MV_PANTHER QSysInfo__MacVersion = 5
QSysInfo__MV_TIGER QSysInfo__MacVersion = 6
QSysInfo__MV_LEOPARD QSysInfo__MacVersion = 7
QSysInfo__MV_SNOWLEOPARD QSysInfo__MacVersion = 8
QSysInfo__MV_LION QSysInfo__MacVersion = 9
QSysInfo__MV_MOUNTAINLION QSysInfo__MacVersion = 10
QSysInfo__MV_MAVERICKS QSysInfo__MacVersion = 11
QSysInfo__MV_YOSEMITE QSysInfo__MacVersion = 12
QSysInfo__MV_ELCAPITAN QSysInfo__MacVersion = 13
QSysInfo__MV_SIERRA QSysInfo__MacVersion = 14
QSysInfo__MV_IOS QSysInfo__MacVersion = 256
QSysInfo__MV_IOS_4_3 QSysInfo__MacVersion = 323
QSysInfo__MV_IOS_5_0 QSysInfo__MacVersion = 336
QSysInfo__MV_IOS_5_1 QSysInfo__MacVersion = 337
QSysInfo__MV_IOS_6_0 QSysInfo__MacVersion = 352
QSysInfo__MV_IOS_6_1 QSysInfo__MacVersion = 353
QSysInfo__MV_IOS_7_0 QSysInfo__MacVersion = 368
QSysInfo__MV_IOS_7_1 QSysInfo__MacVersion = 369
QSysInfo__MV_IOS_8_0 QSysInfo__MacVersion = 384
QSysInfo__MV_IOS_8_1 QSysInfo__MacVersion = 385
QSysInfo__MV_IOS_8_2 QSysInfo__MacVersion = 386
QSysInfo__MV_IOS_8_3 QSysInfo__MacVersion = 387
QSysInfo__MV_IOS_8_4 QSysInfo__MacVersion = 388
QSysInfo__MV_IOS_9_0 QSysInfo__MacVersion = 400
QSysInfo__MV_IOS_9_1 QSysInfo__MacVersion = 401
QSysInfo__MV_IOS_9_2 QSysInfo__MacVersion = 402
QSysInfo__MV_IOS_9_3 QSysInfo__MacVersion = 403
QSysInfo__MV_IOS_10_0 QSysInfo__MacVersion = 416
QSysInfo__MV_TVOS QSysInfo__MacVersion = 512
QSysInfo__MV_TVOS_9_0 QSysInfo__MacVersion = 656
QSysInfo__MV_TVOS_9_1 QSysInfo__MacVersion = 657
QSysInfo__MV_TVOS_9_2 QSysInfo__MacVersion = 658
QSysInfo__MV_TVOS_10_0 QSysInfo__MacVersion = 672
QSysInfo__MV_WATCHOS QSysInfo__MacVersion = 1024
QSysInfo__MV_WATCHOS_2_0 QSysInfo__MacVersion = 1056
QSysInfo__MV_WATCHOS_2_1 QSysInfo__MacVersion = 1057
QSysInfo__MV_WATCHOS_2_2 QSysInfo__MacVersion = 1058
QSysInfo__MV_WATCHOS_3_0 QSysInfo__MacVersion = 1072
)
type QSysInfo struct {
h *C.QSysInfo
}
func (this *QSysInfo) cPointer() *C.QSysInfo {
if this == nil {
return nil
}
return this.h
}
func (this *QSysInfo) UnsafePointer() unsafe.Pointer {
if this == nil {
return nil
}
return unsafe.Pointer(this.h)
}
// newQSysInfo constructs the type using only CGO pointers.
func newQSysInfo(h *C.QSysInfo) *QSysInfo {
if h == nil {
return nil
}
return &QSysInfo{h: h}
}
// UnsafeNewQSysInfo constructs the type using only unsafe pointers.
func UnsafeNewQSysInfo(h unsafe.Pointer) *QSysInfo {
return newQSysInfo((*C.QSysInfo)(h))
}
func QSysInfo_WindowsVersion() QSysInfo__WinVersion {
return (QSysInfo__WinVersion)(C.QSysInfo_windowsVersion())
}
func QSysInfo_MacVersion() QSysInfo__MacVersion {
return (QSysInfo__MacVersion)(C.QSysInfo_macVersion())
}
func QSysInfo_BuildCpuArchitecture() string {
var _ms C.struct_miqt_string = C.QSysInfo_buildCpuArchitecture()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_CurrentCpuArchitecture() string {
var _ms C.struct_miqt_string = C.QSysInfo_currentCpuArchitecture()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_BuildAbi() string {
var _ms C.struct_miqt_string = C.QSysInfo_buildAbi()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_KernelType() string {
var _ms C.struct_miqt_string = C.QSysInfo_kernelType()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_KernelVersion() string {
var _ms C.struct_miqt_string = C.QSysInfo_kernelVersion()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_ProductType() string {
var _ms C.struct_miqt_string = C.QSysInfo_productType()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_ProductVersion() string {
var _ms C.struct_miqt_string = C.QSysInfo_productVersion()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_PrettyProductName() string {
var _ms C.struct_miqt_string = C.QSysInfo_prettyProductName()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_MachineHostName() string {
var _ms C.struct_miqt_string = C.QSysInfo_machineHostName()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_MachineUniqueId() []byte {
var _bytearray C.struct_miqt_string = C.QSysInfo_machineUniqueId()
_ret := C.GoBytes(unsafe.Pointer(_bytearray.data), C.int(int64(_bytearray.len)))
C.free(unsafe.Pointer(_bytearray.data))
return _ret
}
func QSysInfo_BootUniqueId() []byte {
var _bytearray C.struct_miqt_string = C.QSysInfo_bootUniqueId()
_ret := C.GoBytes(unsafe.Pointer(_bytearray.data), C.int(int64(_bytearray.len)))
C.free(unsafe.Pointer(_bytearray.data))
return _ret
}
// Delete this object from C++ memory.
func (this *QSysInfo) Delete() {
C.QSysInfo_delete(this.h)
}
// GoGC adds a Go Finalizer to this pointer, so that it will be deleted
// from C++ memory once it is unreachable from Go memory.
func (this *QSysInfo) GoGC() {
runtime.SetFinalizer(this, func(this *QSysInfo) {
this.Delete()
runtime.KeepAlive(this.h)
})
}

42
qt/gen_qsysinfo.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#ifndef MIQT_QT_GEN_QSYSINFO_H
#define MIQT_QT_GEN_QSYSINFO_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "../libmiqt/libmiqt.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
class QSysInfo;
#else
typedef struct QSysInfo QSysInfo;
#endif
int QSysInfo_windowsVersion();
int QSysInfo_macVersion();
struct miqt_string QSysInfo_buildCpuArchitecture();
struct miqt_string QSysInfo_currentCpuArchitecture();
struct miqt_string QSysInfo_buildAbi();
struct miqt_string QSysInfo_kernelType();
struct miqt_string QSysInfo_kernelVersion();
struct miqt_string QSysInfo_productType();
struct miqt_string QSysInfo_productVersion();
struct miqt_string QSysInfo_prettyProductName();
struct miqt_string QSysInfo_machineHostName();
struct miqt_string QSysInfo_machineUniqueId();
struct miqt_string QSysInfo_bootUniqueId();
void QSysInfo_delete(QSysInfo* self);
#ifdef __cplusplus
} /* extern C */
#endif
#endif

View File

@ -1,3 +1 @@
package qt6
type QSysInfo__Endian int

11
qt6/gen_qglobalstatic.cpp Normal file
View File

@ -0,0 +1,11 @@
#include <qglobalstatic.h>
#include "gen_qglobalstatic.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif

18
qt6/gen_qglobalstatic.go Normal file
View File

@ -0,0 +1,18 @@
package qt6
/*
#include "gen_qglobalstatic.h"
#include <stdlib.h>
*/
import "C"
type QtGlobalStatic__GuardValues int
const (
QtGlobalStatic__Destroyed QtGlobalStatic__GuardValues = -2
QtGlobalStatic__Initialized QtGlobalStatic__GuardValues = -1
QtGlobalStatic__Uninitialized QtGlobalStatic__GuardValues = 0
QtGlobalStatic__Initializing QtGlobalStatic__GuardValues = 1
)

25
qt6/gen_qglobalstatic.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#ifndef MIQT_QT6_GEN_QGLOBALSTATIC_H
#define MIQT_QT6_GEN_QGLOBALSTATIC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "../libmiqt/libmiqt.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
#else
#endif
#ifdef __cplusplus
} /* extern C */
#endif
#endif

137
qt6/gen_qsysinfo.cpp Normal file
View File

@ -0,0 +1,137 @@
#include <QByteArray>
#include <QString>
#include <QByteArray>
#include <cstring>
#include <QSysInfo>
#include <qsysinfo.h>
#include "gen_qsysinfo.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif
struct miqt_string QSysInfo_buildCpuArchitecture() {
QString _ret = QSysInfo::buildCpuArchitecture();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_currentCpuArchitecture() {
QString _ret = QSysInfo::currentCpuArchitecture();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_buildAbi() {
QString _ret = QSysInfo::buildAbi();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_kernelType() {
QString _ret = QSysInfo::kernelType();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_kernelVersion() {
QString _ret = QSysInfo::kernelVersion();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_productType() {
QString _ret = QSysInfo::productType();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_productVersion() {
QString _ret = QSysInfo::productVersion();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_prettyProductName() {
QString _ret = QSysInfo::prettyProductName();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_machineHostName() {
QString _ret = QSysInfo::machineHostName();
// Convert QString from UTF-16 in C++ RAII memory to UTF-8 in manually-managed C memory
QByteArray _b = _ret.toUtf8();
struct miqt_string _ms;
_ms.len = _b.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _b.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_machineUniqueId() {
QByteArray _qb = QSysInfo::machineUniqueId();
struct miqt_string _ms;
_ms.len = _qb.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _qb.data(), _ms.len);
return _ms;
}
struct miqt_string QSysInfo_bootUniqueId() {
QByteArray _qb = QSysInfo::bootUniqueId();
struct miqt_string _ms;
_ms.len = _qb.length();
_ms.data = static_cast<char*>(malloc(_ms.len));
memcpy(_ms.data, _qb.data(), _ms.len);
return _ms;
}
void QSysInfo_delete(QSysInfo* self) {
delete self;
}

151
qt6/gen_qsysinfo.go Normal file
View File

@ -0,0 +1,151 @@
package qt6
/*
#include "gen_qsysinfo.h"
#include <stdlib.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
type QSysInfo__Sizes int
const (
QSysInfo__WordSize QSysInfo__Sizes = 64
)
type QSysInfo__Endian int
const (
QSysInfo__BigEndian QSysInfo__Endian = 0
QSysInfo__LittleEndian QSysInfo__Endian = 1
QSysInfo__ByteOrder QSysInfo__Endian = 1
)
type QSysInfo struct {
h *C.QSysInfo
}
func (this *QSysInfo) cPointer() *C.QSysInfo {
if this == nil {
return nil
}
return this.h
}
func (this *QSysInfo) UnsafePointer() unsafe.Pointer {
if this == nil {
return nil
}
return unsafe.Pointer(this.h)
}
// newQSysInfo constructs the type using only CGO pointers.
func newQSysInfo(h *C.QSysInfo) *QSysInfo {
if h == nil {
return nil
}
return &QSysInfo{h: h}
}
// UnsafeNewQSysInfo constructs the type using only unsafe pointers.
func UnsafeNewQSysInfo(h unsafe.Pointer) *QSysInfo {
return newQSysInfo((*C.QSysInfo)(h))
}
func QSysInfo_BuildCpuArchitecture() string {
var _ms C.struct_miqt_string = C.QSysInfo_buildCpuArchitecture()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_CurrentCpuArchitecture() string {
var _ms C.struct_miqt_string = C.QSysInfo_currentCpuArchitecture()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_BuildAbi() string {
var _ms C.struct_miqt_string = C.QSysInfo_buildAbi()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_KernelType() string {
var _ms C.struct_miqt_string = C.QSysInfo_kernelType()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_KernelVersion() string {
var _ms C.struct_miqt_string = C.QSysInfo_kernelVersion()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_ProductType() string {
var _ms C.struct_miqt_string = C.QSysInfo_productType()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_ProductVersion() string {
var _ms C.struct_miqt_string = C.QSysInfo_productVersion()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_PrettyProductName() string {
var _ms C.struct_miqt_string = C.QSysInfo_prettyProductName()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_MachineHostName() string {
var _ms C.struct_miqt_string = C.QSysInfo_machineHostName()
_ret := C.GoStringN(_ms.data, C.int(int64(_ms.len)))
C.free(unsafe.Pointer(_ms.data))
return _ret
}
func QSysInfo_MachineUniqueId() []byte {
var _bytearray C.struct_miqt_string = C.QSysInfo_machineUniqueId()
_ret := C.GoBytes(unsafe.Pointer(_bytearray.data), C.int(int64(_bytearray.len)))
C.free(unsafe.Pointer(_bytearray.data))
return _ret
}
func QSysInfo_BootUniqueId() []byte {
var _bytearray C.struct_miqt_string = C.QSysInfo_bootUniqueId()
_ret := C.GoBytes(unsafe.Pointer(_bytearray.data), C.int(int64(_bytearray.len)))
C.free(unsafe.Pointer(_bytearray.data))
return _ret
}
// Delete this object from C++ memory.
func (this *QSysInfo) Delete() {
C.QSysInfo_delete(this.h)
}
// GoGC adds a Go Finalizer to this pointer, so that it will be deleted
// from C++ memory once it is unreachable from Go memory.
func (this *QSysInfo) GoGC() {
runtime.SetFinalizer(this, func(this *QSysInfo) {
this.Delete()
runtime.KeepAlive(this.h)
})
}

40
qt6/gen_qsysinfo.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#ifndef MIQT_QT6_GEN_QSYSINFO_H
#define MIQT_QT6_GEN_QSYSINFO_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "../libmiqt/libmiqt.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
class QSysInfo;
#else
typedef struct QSysInfo QSysInfo;
#endif
struct miqt_string QSysInfo_buildCpuArchitecture();
struct miqt_string QSysInfo_currentCpuArchitecture();
struct miqt_string QSysInfo_buildAbi();
struct miqt_string QSysInfo_kernelType();
struct miqt_string QSysInfo_kernelVersion();
struct miqt_string QSysInfo_productType();
struct miqt_string QSysInfo_productVersion();
struct miqt_string QSysInfo_prettyProductName();
struct miqt_string QSysInfo_machineHostName();
struct miqt_string QSysInfo_machineUniqueId();
struct miqt_string QSysInfo_bootUniqueId();
void QSysInfo_delete(QSysInfo* self);
#ifdef __cplusplus
} /* extern C */
#endif
#endif

View File

@ -18,12 +18,12 @@ QQmlListReference* QQmlListReference_new() {
return new QQmlListReference();
}
QQmlListReference* QQmlListReference_new2(QVariant* variant) {
return new QQmlListReference(*variant);
QQmlListReference* QQmlListReference_new2(QVariant* variant, QQmlEngine* engine) {
return new QQmlListReference(*variant, engine);
}
QQmlListReference* QQmlListReference_new3(QObject* o, const char* property) {
return new QQmlListReference(o, property);
QQmlListReference* QQmlListReference_new3(QObject* o, const char* property, QQmlEngine* engine) {
return new QQmlListReference(o, property, engine);
}
QQmlListReference* QQmlListReference_new4(QVariant* variant) {
@ -38,14 +38,6 @@ QQmlListReference* QQmlListReference_new6(QQmlListReference* param1) {
return new QQmlListReference(*param1);
}
QQmlListReference* QQmlListReference_new7(QVariant* variant, QQmlEngine* engine) {
return new QQmlListReference(*variant, engine);
}
QQmlListReference* QQmlListReference_new8(QObject* o, const char* property, QQmlEngine* engine) {
return new QQmlListReference(o, property, engine);
}
void QQmlListReference_operatorAssign(QQmlListReference* self, QQmlListReference* param1) {
self->operator=(*param1);
}

View File

@ -53,17 +53,17 @@ func NewQQmlListReference() *QQmlListReference {
}
// NewQQmlListReference2 constructs a new QQmlListReference object.
func NewQQmlListReference2(variant *qt6.QVariant) *QQmlListReference {
func NewQQmlListReference2(variant *qt6.QVariant, engine *QQmlEngine) *QQmlListReference {
return newQQmlListReference(C.QQmlListReference_new2((*C.QVariant)(variant.UnsafePointer())))
return newQQmlListReference(C.QQmlListReference_new2((*C.QVariant)(variant.UnsafePointer()), engine.cPointer()))
}
// NewQQmlListReference3 constructs a new QQmlListReference object.
func NewQQmlListReference3(o *qt6.QObject, property string) *QQmlListReference {
func NewQQmlListReference3(o *qt6.QObject, property string, engine *QQmlEngine) *QQmlListReference {
property_Cstring := C.CString(property)
defer C.free(unsafe.Pointer(property_Cstring))
return newQQmlListReference(C.QQmlListReference_new3((*C.QObject)(o.UnsafePointer()), property_Cstring))
return newQQmlListReference(C.QQmlListReference_new3((*C.QObject)(o.UnsafePointer()), property_Cstring, engine.cPointer()))
}
// NewQQmlListReference4 constructs a new QQmlListReference object.
@ -86,20 +86,6 @@ func NewQQmlListReference6(param1 *QQmlListReference) *QQmlListReference {
return newQQmlListReference(C.QQmlListReference_new6(param1.cPointer()))
}
// NewQQmlListReference7 constructs a new QQmlListReference object.
func NewQQmlListReference7(variant *qt6.QVariant, engine *QQmlEngine) *QQmlListReference {
return newQQmlListReference(C.QQmlListReference_new7((*C.QVariant)(variant.UnsafePointer()), engine.cPointer()))
}
// NewQQmlListReference8 constructs a new QQmlListReference object.
func NewQQmlListReference8(o *qt6.QObject, property string, engine *QQmlEngine) *QQmlListReference {
property_Cstring := C.CString(property)
defer C.free(unsafe.Pointer(property_Cstring))
return newQQmlListReference(C.QQmlListReference_new8((*C.QObject)(o.UnsafePointer()), property_Cstring, engine.cPointer()))
}
func (this *QQmlListReference) OperatorAssign(param1 *QQmlListReference) {
C.QQmlListReference_operatorAssign(this.h, param1.cPointer())
}

View File

@ -29,13 +29,11 @@ typedef struct QVariant QVariant;
#endif
QQmlListReference* QQmlListReference_new();
QQmlListReference* QQmlListReference_new2(QVariant* variant);
QQmlListReference* QQmlListReference_new3(QObject* o, const char* property);
QQmlListReference* QQmlListReference_new2(QVariant* variant, QQmlEngine* engine);
QQmlListReference* QQmlListReference_new3(QObject* o, const char* property, QQmlEngine* engine);
QQmlListReference* QQmlListReference_new4(QVariant* variant);
QQmlListReference* QQmlListReference_new5(QObject* o, const char* property);
QQmlListReference* QQmlListReference_new6(QQmlListReference* param1);
QQmlListReference* QQmlListReference_new7(QVariant* variant, QQmlEngine* engine);
QQmlListReference* QQmlListReference_new8(QObject* o, const char* property, QQmlEngine* engine);
void QQmlListReference_operatorAssign(QQmlListReference* self, QQmlListReference* param1);
bool QQmlListReference_isValid(const QQmlListReference* self);
QObject* QQmlListReference_object(const QQmlListReference* self);