Skip to content

Commit

Permalink
Merge pull request #138 from tishin/win-createprocess-fix
Browse files Browse the repository at this point in the history
Fix process argument limit error when building on Windows
  • Loading branch information
migueldeicaza authored Sep 30, 2023
2 parents 242a8a3 + d8a2707 commit 77feb71
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 39 deletions.
8 changes: 5 additions & 3 deletions Generator/Generator/BuiltinGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ enum BKind {
var builtinGodotTypeNames: [String:BKind] = ["Variant": .isClass]
var builtinClassStorage: [String:String] = [:]

func generateBuiltinClasses (values: [JGodotBuiltinClass], outputDir: String) {
func generateBuiltinClasses (values: [JGodotBuiltinClass], outputDir: String?) async {

func generateBuiltinClass (p: Printer, _ bc: JGodotBuiltinClass, _ docClass: DocBuiltinClass?) {
// TODO: isKeyed, hasDestrcturo,
Expand Down Expand Up @@ -623,13 +623,15 @@ func generateBuiltinClasses (values: [JGodotBuiltinClass], outputDir: String) {
case "int", "float", "bool":
break
default:
let p = Printer ()
let p: Printer = await PrinterFactory.shared.initPrinter()
p.preamble()
let docClass = loadBuiltinDoc(base: docRoot, name: bc.name)
mapStringToSwift = bc.name != "String"
generateBuiltinClass (p: p, bc, docClass)
mapStringToSwift = true
p.save(outputDir + "/\(bc.name).swift")
if let outputDir {
p.save(outputDir + "/\(bc.name).swift")
}
}
}
}
24 changes: 10 additions & 14 deletions Generator/Generator/ClassGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ var okList = [ "RefCounted", "Node", "Sprite2D", "Node2D", "CanvasItem", "Object
var okList: [String] = []
#endif

func generateClasses (values: [JGodotExtensionAPIClass], outputDir: String) {
func generateClasses (values: [JGodotExtensionAPIClass], outputDir: String?) async {
// TODO: duplicate, we can remove this and use classMap
// Assemble all the reference types, we use to test later
for cdef in values {
Expand Down Expand Up @@ -447,19 +447,13 @@ func generateClasses (values: [JGodotExtensionAPIClass], outputDir: String) {
// }
// }

let semaphore = DispatchSemaphore(value: 0)

let _ = Task {
await withTaskGroup(of: Void.self) { group in
for cdef in values {
group.addTask {
processClass (cdef: cdef, outputDir: outputDir)
}
await withTaskGroup(of: Void.self) { group in
for cdef in values {
group.addTask {
await processClass (cdef: cdef, outputDir: outputDir)
}
}
semaphore.signal()
}
semaphore.wait()
}

func generateSignalType (_ p: Printer, _ cdef: JGodotExtensionAPIClass, _ signal: JGodotSignal, _ name: String) -> String {
Expand Down Expand Up @@ -592,21 +586,23 @@ func generateSignalDocAppendix (_ p: Printer, cdef: JGodotExtensionAPIClass, sig
}
}

func processClass (cdef: JGodotExtensionAPIClass, outputDir: String) {
func processClass (cdef: JGodotExtensionAPIClass, outputDir: String?) async {
let docClass = loadClassDoc(base: docRoot, name: cdef.name)

// Determine if it is a singleton, but exclude EditorInterface
let isSingleton = jsonApi.singletons.contains (where: { $0.name == cdef.name })
let asSingleton = isSingleton && cdef.name != "EditorInterface"

// Clear the result
let p = Printer ()
let p = await PrinterFactory.shared.initPrinter()
p.preamble()
p ("// Generated by Swift code generator - do not edit\n@_implementationOnly import GDExtension\n")

// Save it
defer {
p.save(outputDir + "\(cdef.name).swift")
if let outputDir {
p.save(outputDir + "\(cdef.name).swift")
}
}

let inherits = cdef.inherits ?? "Wrapped"
Expand Down
26 changes: 25 additions & 1 deletion Generator/Generator/Printer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

public class Printer {
class Printer {
// Where we accumulate our output for the p/b routines
var result = ""
var indentStr = "" // The current indentation string, based on `indent`
Expand All @@ -16,6 +16,8 @@ public class Printer {
indentStr = String (repeating: " ", count: indent)
}
}

fileprivate init() {}

func preamble () {
p ("// This file is autogenerated, do not edit\n")
Expand Down Expand Up @@ -60,3 +62,25 @@ public class Printer {
try! result.write(toFile: file, atomically: true, encoding: .utf8)
}
}

actor PrinterFactory {
static let shared = PrinterFactory()

private var printers: [Printer] = []

func initPrinter() -> Printer {
let printer = Printer()
printers.append(printer)
return printer
}

func save (_ file: String) {
let result = printers.map({ $0.result }).joined(separator: "\n")
if let existing = try? String (contentsOfFile: file) {
if existing == result {
return
}
}
try! result.write(toFile: file, atomically: true, encoding: .utf8)
}
}
8 changes: 5 additions & 3 deletions Generator/Generator/UtilityGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

import Foundation

func generateUtility(values: [JGodotUtilityFunction], outputDir: String) {
let p = Printer ()
func generateUtility(values: [JGodotUtilityFunction], outputDir: String?) async {
let p = await PrinterFactory.shared.initPrinter()
p.preamble()
defer {
p.save (outputDir + "utility.swift")
if let outputDir {
p.save (outputDir + "utility.swift")
}
}

let docClass = loadClassDoc(base: docRoot, name: "@GlobalScope")
Expand Down
47 changes: 30 additions & 17 deletions Generator/Generator/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
//
import Foundation

// IF we want a single file, or one file per type
var singleFile = true

var args = CommandLine.arguments

let jsonFile = args.count > 1 ? args [1] : "/Users/miguel/cvs/godot-master/extension_api.json"
Expand All @@ -18,6 +15,9 @@ var docRoot = args.count > 3 ? args [3] : "/Users/miguel/cvs/godot-master/doc"

let outputDir = args.count > 2 ? args [2] : generatorOutput

// IF we want a single file, or one file per type
var singleFile = args.contains("--singlefile")

if args.count < 2 {
print ("Usage is: generator path-to-extension-api output-directory doc-directory")
print ("- path-to-extensiona-ppi is the full path to extension_api.json from Godot")
Expand Down Expand Up @@ -55,9 +55,6 @@ func dropMatchingPrefix (_ enumName: String, _ enumKey: String) -> String {

var globalEnums: [String: JGodotGlobalEnumElement] = [:]

var coreDefPrinter = Printer()
coreDefPrinter.preamble()

print ("Running with projectDir=$(projectDir) and output=\(outputDir)")
let globalDocs = loadClassDoc(base: docRoot, name: "@GlobalScope")
var classMap: [String:JGodotExtensionAPIClass] = [:]
Expand All @@ -66,7 +63,6 @@ for x in jsonApi.classes {
}

var builtinMap: [String: JGodotBuiltinClass] = [:]
generateEnums(coreDefPrinter, cdef: nil, values: jsonApi.globalEnums, constantDocs: globalDocs?.constants?.constant, prefix: "")

for x in jsonApi.builtinClasses {
let value = x.members?.count ?? 0 > 0
Expand All @@ -86,17 +82,34 @@ for cs in jsonApi.builtinClassSizes {
}
}

let generatedBuiltinDir = outputDir + "/generated-builtin/"
let generatedDir = outputDir + "/generated/"
let generatedBuiltinDir: String? = singleFile ? nil : (outputDir + "/generated-builtin/")
let generatedDir: String? = singleFile ? nil : (outputDir + "/generated/")

try! FileManager.default.createDirectory(atPath: generatedBuiltinDir, withIntermediateDirectories: true)
try! FileManager.default.createDirectory(atPath: generatedDir, withIntermediateDirectories: true)

generateBuiltinClasses(values: jsonApi.builtinClasses, outputDir: generatedBuiltinDir)
generateUtility(values: jsonApi.utilityFunctions, outputDir: generatedBuiltinDir)
generateClasses (values: jsonApi.classes, outputDir: generatedDir)
if singleFile {
try! FileManager.default.createDirectory(atPath: outputDir, withIntermediateDirectories: true)
} else if let generatedBuiltinDir, let generatedDir {
try! FileManager.default.createDirectory(atPath: generatedBuiltinDir, withIntermediateDirectories: true)
try! FileManager.default.createDirectory(atPath: generatedDir, withIntermediateDirectories: true)
}

generateCtorPointers (coreDefPrinter)
coreDefPrinter.save (generatedBuiltinDir + "/core-defs.swift")
let semaphore = DispatchSemaphore(value: 0)
let _ = Task {
let coreDefPrinter = await PrinterFactory.shared.initPrinter()
coreDefPrinter.preamble()
generateEnums(coreDefPrinter, cdef: nil, values: jsonApi.globalEnums, constantDocs: globalDocs?.constants?.constant, prefix: "")
await generateBuiltinClasses(values: jsonApi.builtinClasses, outputDir: generatedBuiltinDir)
await generateUtility(values: jsonApi.utilityFunctions, outputDir: generatedBuiltinDir)
await generateClasses (values: jsonApi.classes, outputDir: generatedDir)
generateCtorPointers (coreDefPrinter)
if let generatedBuiltinDir {
coreDefPrinter.save (generatedBuiltinDir + "/core-defs.swift")
}

if singleFile {
await PrinterFactory.shared.save(outputDir + "/generated.swift")
}
semaphore.signal()
}
semaphore.wait()

//print ("Done")
10 changes: 9 additions & 1 deletion Plugins/CodeGeneratorPlugin/plugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@ import PackagePlugin

let api = context.package.directory.appending(["Sources", "SwiftGodot", "extension_api.json"])

var arguments: [CustomStringConvertible] = [ api, genSourcesDir ]
var outputFiles: [Path] = []
#if os(Windows)
// Windows has 32K limit on CreateProcess argument length, SPM currently doesn't handle it well
outputFiles.append(genSourcesDir.appending(subpath: "Generated.swift"))
arguments.append(context.package.directory.appending(subpath: "doc"))
arguments.append("--singlefile")
#else
outputFiles.append (contentsOf: knownBuiltin.map { genSourcesDir.appending(["generated-builtin", $0])})
outputFiles.append (contentsOf: known.map { genSourcesDir.appending(["generated", $0])})
#endif

let cmd: Command = Command.buildCommand(
displayName: "Generating Swift API ffrom \(api) to \(genSourcesDir)",
executable: generator,
arguments: [ api, genSourcesDir ],
arguments: arguments,
inputFiles: [api],
outputFiles: outputFiles)

Expand Down

0 comments on commit 77feb71

Please sign in to comment.