Skip to content

Commit 91bc7ac

Browse files
committed
generate: add structs tool
1 parent 5cbb735 commit 91bc7ac

File tree

6 files changed

+157
-65
lines changed

6 files changed

+157
-65
lines changed

docs/generation.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ Once it generates good output, you can pipe it to the appropriate file under ./g
115115

116116
The [initmod](#initmod-platform-framework) tool can now be run to generate the initial files for the package that are not intended to be generated again. At this point you won't have to modify anything in these yet, they're good as is.
117117

118+
This is also where you should generate structs. This is done out of band from regular generation
119+
so that they can be tweaked manually if needed. You can use the [structs](#structs) tool like this:
120+
121+
`go run ./generate/tools/structs.go [framework] > ./macos/[framework]/[framework]_structs.go`
122+
123+
Be sure to check the output! If it was unable to generate a struct it will include it in the comments at the bottom. If any other struct has a field using a struct type it couldn't generate it will start with ` _Ctype_struct_`, which you'll need to comment out or replace with a placeholder until you have that type.
124+
118125

119126
### Step 4: Run go generate for your framework
120127

@@ -220,8 +227,8 @@ Re-generates frameworks that have been generated (have .gen.go files).
220227

221228
`./generate/tools/regen.sh macos`
222229

223-
### findstruct [struct-name]
230+
### structs [framework]
224231

225-
Looks through XCode SDK headers for a struct definition. Helpful to fill in struct definitions.
232+
Generates documented Go structs for a framework.
226233

227-
`go run ./generate/tools/findstruct.go CLLocationCoordinate2D`
234+
`go run ./generate/tools/structs.go foundation > ./macos/foundation/foundation_structs.go`

generate/generator.go

+3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ func (db *Generator) Generate(platform string, version int, rootDir string, fram
136136
})
137137
continue
138138
}
139+
// any other type aliases can be added manually
140+
// since they're just a go type alias or an
141+
// unsafe.Pointer type
139142
}
140143
}
141144
mw.WriteCode()

generate/modules/modules.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ var All = []Module{
148148
{"AVFoundation", "AVFoundation", "avfoundation", "AVFoundation/AVFoundation.h", []string{"AV"}},
149149
{"AVKit", "AVKit", "avkit", "AVKit/AVKit.h", []string{"AV"}},
150150
{"GameplayKit", "GameplayKit", "gameplaykit", "GameplayKit/GameplayKit.h", []string{"GK"}},
151+
{"SystemConfiguration", "System Configuration", "sysconfig", "SystemConfiguration/SystemConfiguration.h", []string{"SC", "kSC"}},
151152
{"SceneKit", "SceneKit", "scenekit", "SceneKit/SceneKit.h", []string{"SCN"}},
152153
{"SpriteKit", "SpriteKit", "spritekit", "SpriteKit/SpriteKit.h", []string{"SK"}},
153154
{"ModelIO", "Model I/O", "modelio", "ModelIO/ModelIO.h", []string{"MDL"}},
@@ -156,6 +157,5 @@ var All = []Module{
156157
{"MetalKit", "Metal Kit", "metalkit", "MetalKit/MetalKit.h", []string{"MTK"}},
157158
{"MetalPerformanceShadersGraph", "Metal Performance Shaders Graph", "mpsgraph", "MetalPerformanceShadersGraph/MetalPerformanceShadersGraph.h", []string{"MPSGraph"}},
158159
{"MetalPerformanceShaders", "Metal Performance Shaders", "mps", "MetalPerformanceShaders/MetalPerformanceShaders.h", []string{"MPS"}},
159-
{"SystemConfiguration", "System Configuration", "sysconfig", "SystemConfiguration/SystemConfiguration.h", []string{"SC", "kSC"}},
160160
{"MediaPlayer", "Media Player", "mediaplayer", "MediaPlayer/MediaPlayer.h", []string{"MP"}},
161161
}

generate/symbols.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var pathBlacklist = []string{
4545
type Symbol struct {
4646
Name string
4747
Path string
48-
Kind string
48+
Kind string // Class, Constant, Enum, Framework, Function, Macro, Method, Property, Protocol, Struct, Type
4949

5050
Description string
5151
Type string

generate/tools/findstruct.go

-60
This file was deleted.

generate/tools/structs.go

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//go:build ignore
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
"io/ioutil"
8+
"log"
9+
"os"
10+
"os/exec"
11+
"strings"
12+
13+
"github.com/progrium/macdriver/generate"
14+
"github.com/progrium/macdriver/generate/modules"
15+
)
16+
17+
const TargetPlatform = "macos"
18+
const TargetVersion = 12
19+
20+
// go run ./generate/tools/structs.go [framework]
21+
func main() {
22+
23+
db, err := generate.OpenSymbols("./generate/symbols.zip")
24+
if err != nil {
25+
log.Fatal(err)
26+
}
27+
defer db.Close()
28+
29+
if len(os.Args) > 1 {
30+
mod := modules.Get(strings.ToLower(os.Args[1]))
31+
32+
var structDefs []string
33+
var badStructs []string
34+
docComments := make(map[string]string)
35+
36+
for _, s := range db.ModuleSymbols(mod.Package) {
37+
if TargetPlatform == "macos" && mod.Package == "uikit" {
38+
// we're going to pretend to be appkit later
39+
// to handle the uikit symbols existing in appkit
40+
if !s.HasFramework("appkit") {
41+
continue
42+
}
43+
}
44+
if !s.HasPlatform(TargetPlatform, TargetVersion, true) {
45+
continue
46+
}
47+
48+
if s.Kind == "Struct" {
49+
50+
structDef := fmt.Sprintf("type %s C.%s\n", modules.TrimPrefix(s.Name), s.Name)
51+
52+
// generate for just this struct to see that it works
53+
// before adding so the full list generates without error.
54+
// however we can't just use this because godefs will only
55+
// use the right sub struct type if they're generated together.
56+
_, err := goDefsFor(mod, []string{structDef})
57+
if err != nil {
58+
badStructs = append(badStructs, s.Name)
59+
continue
60+
}
61+
62+
if s.DocURL() != "" {
63+
// godefs strips comments so we'll have to reassemble with
64+
// comments using this
65+
docComments[modules.TrimPrefix(s.Name)] = fmt.Sprintf("// %s [Full Topic]\n//\n// [Full Topic]: %s\n", s.Description, s.DocURL())
66+
}
67+
68+
structDefs = append(structDefs, structDef)
69+
}
70+
}
71+
72+
if len(structDefs) == 0 {
73+
fmt.Fprintln(os.Stderr, "No structs for this framework")
74+
os.Exit(1)
75+
}
76+
77+
out, err := goDefsFor(mod, structDefs)
78+
if err != nil {
79+
fmt.Println(out)
80+
log.Fatal(err)
81+
}
82+
83+
// *byte and *[0]byte fields should just be uintptr
84+
out = strings.ReplaceAll(out, "*byte", "uintptr")
85+
out = strings.ReplaceAll(out, "*[0]byte", "uintptr")
86+
87+
// reassemble with comments
88+
fmt.Println("package", mod.Package, "\n")
89+
parts := strings.Split(out, "type ")
90+
for _, p := range parts[1:] {
91+
words := strings.Fields(p)
92+
if s, ok := docComments[words[0]]; ok {
93+
fmt.Print(s)
94+
}
95+
fmt.Println("type", p)
96+
}
97+
98+
if len(badStructs) > 0 {
99+
fmt.Println("// TODO (unable to generate):")
100+
fmt.Println("//", strings.Join(badStructs, " "))
101+
}
102+
}
103+
104+
}
105+
106+
func goDefsFor(mod *modules.Module, structDefs []string) (string, error) {
107+
extraLoad := ""
108+
extraInclude := ""
109+
source := fmt.Sprintf(`package main
110+
111+
/*
112+
#cgo CFLAGS: -w -x objective-c
113+
#cgo LDFLAGS: -lobjc -framework %s %s
114+
#include <%s>
115+
%s
116+
*/
117+
import "C"
118+
119+
%s
120+
`, mod.Name, extraLoad, mod.Header, extraInclude, strings.Join(structDefs, "\n"))
121+
b, err := evalSource(source)
122+
return string(b), err
123+
}
124+
125+
func evalSource(source string) ([]byte, error) {
126+
tempFile, err := ioutil.TempFile("", "temp-code-*.go")
127+
if err != nil {
128+
log.Fatal("Failed to create temporary file:", err)
129+
}
130+
defer os.Remove(tempFile.Name())
131+
132+
if _, err := tempFile.WriteString(source); err != nil {
133+
log.Fatal("Failed to write to temporary file:", err)
134+
}
135+
136+
if err := tempFile.Close(); err != nil {
137+
log.Fatal("Failed to close temporary file:", err)
138+
}
139+
140+
cmd := exec.Command("go", "tool", "cgo", "-godefs", "--", "-x", "objective-c", tempFile.Name())
141+
return cmd.CombinedOutput()
142+
}

0 commit comments

Comments
 (0)