diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 030fba7e..66d9de2c 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -97,6 +97,21 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo return err } + dynamicGo, err := CreateLanguageFile(path.Join(outputFolder, "dynload.go"), " ") + if err != nil { + return err + } + + dynamicGo.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated Go wrapper file in order to allow an easy\nuse of %s.", component.LibraryName), + true) + + dynamicGo.Writeln("// Code generated by Automatic Component Toolkit (ACT); DO NOT EDIT.") + err = buildGoDynLoad(component, dynamicGo) + if err != nil { + return err + } + GoIntfName := path.Join(outputFolder, component.BaseName+".go") log.Printf("Creating \"%s\"", GoIntfName) gofile, err := CreateLanguageFile(GoIntfName, " ") @@ -134,6 +149,78 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo return nil } +func buildGoDynLoad(component ComponentDefinition, w LanguageWriter) error { + packageName := strings.ToLower(component.BaseName) + + w.Writeln("// +build !act_nodynload") + w.Writeln("") + w.Writeln("package %s", packageName) + w.Writeln("") + w.Writeln("/*") + w.Writeln("#include \"%s_dynamic.cc\"", packageName) + w.Writeln("") + w.Writeln("s%sDynamicWrapperTable * load%sLibrary (const char * pFileName)", component.NameSpace, component.NameSpace) + w.Writeln("{") + w.Writeln(" %sResult nResult;", component.NameSpace) + w.Writeln(" s%sDynamicWrapperTable * pWrapperTable = (s%sDynamicWrapperTable *) malloc (sizeof (s%sDynamicWrapperTable));", component.NameSpace, component.NameSpace, component.NameSpace) + w.Writeln(" if (pWrapperTable != NULL) {") + w.Writeln(" nResult = Init%sWrapperTable (pWrapperTable);", component.NameSpace) + w.Writeln(" if (nResult != %s_SUCCESS) {", strings.ToUpper(component.NameSpace)) + w.Writeln(" free (pWrapperTable);") + w.Writeln(" return 0;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" nResult = Load%sWrapperTable (pWrapperTable, pFileName);", component.NameSpace) + w.Writeln(" if (nResult != %s_SUCCESS) {", strings.ToUpper(component.NameSpace)) + w.Writeln(" free (pWrapperTable);") + w.Writeln(" return 0;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" return pWrapperTable;") + w.Writeln(" }") + w.Writeln("}") + w.Writeln("") + w.Writeln("void unload%sLibrary (s%sDynamicWrapperTable * nLibraryHandle)", component.NameSpace, component.NameSpace) + w.Writeln("{") + w.Writeln(" s%sDynamicWrapperTable * pWrapperTable = (s%sDynamicWrapperTable *) malloc (sizeof (s%sDynamicWrapperTable));", component.NameSpace, component.NameSpace, component.NameSpace) + w.Writeln(" if (pWrapperTable != NULL) {") + w.Writeln(" Release%sWrapperTable (pWrapperTable);", component.NameSpace) + w.Writeln(" free (pWrapperTable);") + w.Writeln(" }") + w.Writeln("}") + w.Writeln("") + + err := writeGoCCalls(component, w) + if err != nil { + return err + } + + w.Writeln("*/") + w.Writeln("import \"C\"") + w.Writeln("import \"unsafe\"") + + w.Writeln("") + w.Writeln("// Wrapper represents the number wrapper") + w.Writeln("type DynamicWrapper struct {") + w.Writeln(" libraryHandle *C.s%sDynamicWrapperTable", component.NameSpace) + w.Writeln("}") + w.Writeln("") + err = writeCGoDynamicMethods(component, w) + if err != nil { + return err + } + w.Writeln("func LoadLibrary(libraryPath string) (Wrapper, error) {") + w.Writeln(" var dw DynamicWrapper") + w.Writeln(" dw.libraryHandle = C.load%sLibrary((*C.char)(unsafe.Pointer(&[]byte(libraryPath)[0])))", component.NameSpace) + w.Writeln(" if dw.libraryHandle == nil {") + w.Writeln(" return Wrapper{}, makeError(%s_ERROR_COULDNOTLOADLIBRARY)", strings.ToUpper(component.NameSpace)) + w.Writeln(" }") + w.Writeln(" return Wrapper{dw}, nil") + w.Writeln("}") + + return nil +} + func buildCFuncsWrapper(component ComponentDefinition, w LanguageWriter) error { packageName := strings.ToLower(component.BaseName) @@ -143,12 +230,10 @@ func buildCFuncsWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("/*") w.Writeln("#include \"%s_types.h\"", packageName) - /* - TODO - err := buildCFuncs(component, w) - if err != nil { - return err - } */ + err := buildCFuncs(component, w) + if err != nil { + return err + } w.Writeln("*/") w.Writeln("import \"C\"") @@ -471,31 +556,62 @@ func WriteCGoAbiMethod(method ComponentDefinitionMethod, w LanguageWriter, NameS return err } for _, cParam := range cParams { - parameters = append(parameters, cParam.ParamType + " " + cParam.ParamName) + parameters = append(parameters, cParam.ParamType+" "+cParam.ParamName) callParameters = append(callParameters, cParam.ParamName) } } w.Writeln("") - w.Writeln("%sResult CCall_%s(%sHandle libraryHandle, %s)", NameSpace, CMethodName, NameSpace, strings.Join(parameters, ", ")) + w.Writeln("%sResult CCall_%s(s%sDynamicWrapperTable * wrapperTable, %s)", NameSpace, CMethodName, NameSpace, strings.Join(parameters, ", ")) w.Writeln("{") - w.Writeln(" if (libraryHandle == 0) ") - w.Writeln(" return %s_ERROR_INVALIDCAST;", strings.ToUpper(NameSpace)) - w.Writeln(" s%sDynamicWrapperTable * wrapperTable = (s%sDynamicWrapperTable *) libraryHandle;", NameSpace, NameSpace) - callParametersStr := strings.Join(callParameters, ", ") if isGlobal { - w.Writeln(" return wrapperTable->m_%s (%s);", method.MethodName, callParametersStr) + w.Writeln(" return wrapperTable->m_%s(%s);", method.MethodName, callParametersStr) } else { - w.Writeln(" return wrapperTable->m_%s_%s (%s);", ClassName, method.MethodName, callParametersStr) + w.Writeln(" return wrapperTable->m_%s_%s(%s);", ClassName, method.MethodName, callParametersStr) } w.Writeln("}") - w.Writeln("") return nil } +func writeCgoerMethods(component ComponentDefinition, w LanguageWriter) error { + for _, class := range component.Classes { + for _, method := range class.Methods { + _, err := writeCGoMethod(method, w, component.NameSpace, class.ClassName, false, false) + if err != nil { + return err + } + } + } + for _, method := range component.Global.Methods { + _, err := writeCGoMethod(method, w, component.NameSpace, "Wrapper", false, true) + if err != nil { + return err + } + } + return nil +} + +func writeCGoDynamicMethods(component ComponentDefinition, w LanguageWriter) error { + for _, class := range component.Classes { + for _, method := range class.Methods { + err := writeCGoDynamic(method, w, component.NameSpace, class.ClassName, false) + if err != nil { + return err + } + } + } + for _, method := range component.Global.Methods { + err := writeCGoDynamic(method, w, component.NameSpace, "Wrapper", true) + if err != nil { + return err + } + } + return nil +} + func writeGoCCall(component ComponentDefinition, method ComponentDefinitionMethod, w LanguageWriter, className string, isGlobal bool) error { err := WriteCGoAbiMethod(method, w, component.NameSpace, className, isGlobal) if err != nil { @@ -520,7 +636,6 @@ func writeGoCCalls(component ComponentDefinition, w LanguageWriter) error { } } return nil - } func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { @@ -533,51 +648,12 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("package %s", packageName) w.Writeln("") w.Writeln("/*") - w.Writeln("#include \"%s_dynamic.cc\"", packageName) - w.Writeln("") - w.Writeln("%sHandle load%sLibrary (const char * pFileName)", component.NameSpace, component.NameSpace) - w.Writeln("{") - w.Writeln(" %sResult nResult;", component.NameSpace) - w.Writeln(" s%sDynamicWrapperTable * pWrapperTable = (s%sDynamicWrapperTable *) malloc (sizeof (s%sDynamicWrapperTable));", component.NameSpace, component.NameSpace, component.NameSpace) - w.Writeln(" if (pWrapperTable != NULL) {") - w.Writeln(" nResult = Init%sWrapperTable (pWrapperTable);", component.NameSpace) - w.Writeln(" if (nResult != %s_SUCCESS) {", strings.ToUpper(component.NameSpace)) - w.Writeln(" free (pWrapperTable);") - w.Writeln(" return 0;") - w.Writeln(" }") - w.Writeln("") - w.Writeln(" nResult = Load%sWrapperTable (pWrapperTable, pFileName);", component.NameSpace) - w.Writeln(" if (nResult != %s_SUCCESS) {", strings.ToUpper(component.NameSpace)) - w.Writeln(" free (pWrapperTable);") - w.Writeln(" return 0;") - w.Writeln(" }") - w.Writeln("") - w.Writeln(" return (%sHandle) pWrapperTable;", component.NameSpace) - w.Writeln(" }") - w.Writeln("}") - w.Writeln("") - w.Writeln("void unload%sLibrary (%sHandle nLibraryHandle)", component.NameSpace, component.NameSpace) - w.Writeln("{") - w.Writeln(" s%sDynamicWrapperTable * pWrapperTable = (s%sDynamicWrapperTable *) malloc (sizeof (s%sDynamicWrapperTable));", component.NameSpace, component.NameSpace, component.NameSpace) - w.Writeln(" if (pWrapperTable != NULL) {") - w.Writeln(" Release%sWrapperTable (pWrapperTable);", component.NameSpace) - w.Writeln(" free (pWrapperTable);") - w.Writeln(" }") - w.Writeln("}") - w.Writeln("") - - /* TODO! + w.Writeln("#include \"%s_types.h\"", packageName) err = buildCFuncsForward(component, w) if err != nil { return err } - */ - - err = writeGoCCalls(component, w) - if err != nil { - return err - } w.Writeln("*/") w.Writeln("import \"C\"") @@ -604,11 +680,18 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { return err } + w.Writeln("") + w.Writeln("type cgoer interface {") + err = writeCgoerMethods(component, w) + if err != nil { + return err + } + + w.Writeln("}") w.Writeln("") w.Writeln("// Wrapper represents the number wrapper") w.Writeln("type Wrapper struct {") - w.Writeln(" _ [0]func() // uncomparable; to make == not compile") - w.Writeln(" LibraryHandle ref") + w.Writeln(" impl cgoer") w.Writeln("}") for _, class := range component.Classes { @@ -648,17 +731,6 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("}") w.Writeln("") - w.Writeln("func LoadLibrary (libraryPath string) (Wrapper, error) {") - w.Writeln(" var wrapper Wrapper;") - w.Writeln(" wrapper.LibraryHandle = C.load%sLibrary (C.CString (libraryPath));", component.NameSpace) - w.Writeln(" if (wrapper.LibraryHandle == nil) {") - w.Writeln(" return wrapper, makeError (%s_ERROR_COULDNOTLOADLIBRARY)", strings.ToUpper(component.NameSpace)) - w.Writeln(" }") - w.Writeln(" ") - w.Writeln(" return wrapper, nil") - w.Writeln(" ") - w.Writeln("}") - return nil } @@ -722,16 +794,16 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( } case "string": tp.Type = ptrStr + "string" - tp.CType = ptrStr + "*C.char" + tp.CType = "*C.char" tp.CToGo = "" tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&[]byte(%s)[0]))", tp.CType, paramName) tp.Empty = "\"\"" case "pointer": - tp.Type = "uint64" - tp.CType = fmt.Sprintf("C.uint64_t") + tp.Type = "unsafe.Pointer" + tp.CType = fmt.Sprintf("C.%s_pvoid", namespace) tp.CToGo = fmt.Sprintf("%s(%s)", tp.Type, paramName) tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) - tp.Empty = "0" + tp.Empty = "nil" case "enum": tp.Type = ptrStr + paramClass tp.CType = fmt.Sprintf("%sC.e%s%s", ptrStr, namespace, paramClass) @@ -755,7 +827,7 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( tp.Empty = paramClass + "{}" case "class": tp.Type = paramClass - tp.CType = fmt.Sprintf("C.%s_%s", namespace, paramClass) + tp.CType = ptrStr + fmt.Sprintf("C.%s_%s", namespace, paramClass) tp.CToGo = "" tp.GoToC = fmt.Sprintf("%s.Ref", paramName) tp.Empty = paramClass + "{}" @@ -823,6 +895,97 @@ func toGoParam(s string) string { return s } +func writeCGoDynamic(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, className string, isGlobal bool) error { + n, err := writeCGoMethod(method, w, NameSpace, className, true, isGlobal) + if err != nil { + return err + } + parameters := make([]string, n+1) + parameters[0] = "dw.libraryHandle" + for i := 0; i < n; i++ { + parameters[i+1] = fmt.Sprintf("p%d", i) + } + fnName := "" + if isGlobal { + fnName = fmt.Sprintf("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) + } else { + fnName = fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(className), strings.ToLower(method.MethodName)) + } + w.Writeln(" return C.CCall_%s(%s)", fnName, strings.Join(parameters, ", ")) + w.Writeln("}") + w.Writeln("") + return nil +} + +func writeCGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, className string, isFunc, isGlobal bool) (int, error) { + var parameters []string + var i int + if !isGlobal { + if isFunc { + parameters = append(parameters, fmt.Sprintf("p%d C.%s_%s", i, NameSpace, className)) + } else { + parameters = append(parameters, fmt.Sprintf("C.%s_%s", NameSpace, className)) + } + i++ + } + for _, param := range method.Params { + param.ParamName = toGoParam(param.ParamName) + isPtr := param.ParamPass == "out" || param.ParamPass == "return" || param.ParamType == "struct" + tp, err := getGoType(param.ParamType, NameSpace, param.ParamClass, param.ParamName, isPtr) + if err != nil { + return 0, err + } + switch param.ParamPass { + case "in": + if param.ParamType == "basicarray" || param.ParamType == "structarray" { + if isFunc { + parameters = append(parameters, fmt.Sprintf("p%d C.uint64_t", i)) + } else { + parameters = append(parameters, "C.uint64_t") + } + i++ + } + case "out", "return": + switch param.ParamType { + case "string": + if isFunc { + parameters = append(parameters, fmt.Sprintf("p%d C.uint32_t", i), fmt.Sprintf("p%d *C.uint32_t", i+1)) + } else { + parameters = append(parameters, "C.uint32_t", "*C.uint32_t") + } + i += 2 + case "basicarray", "structarray": + if isFunc { + parameters = append(parameters, fmt.Sprintf("p%d C.uint64_t", i), fmt.Sprintf("p%d *C.uint64_t", i+1)) + } else { + parameters = append(parameters, "C.uint64_t", "*C.uint64_t") + } + i += 2 + } + } + if isFunc { + parameters = append(parameters, fmt.Sprintf("p%d %s", i, tp.CType)) + } else { + parameters = append(parameters, tp.CType) + } + i++ + } + + fnName := method.MethodName + if !isGlobal { + fnName = className + "_" + fnName + } + var prefix, suffix string + if isFunc { + prefix = "func (dw DynamicWrapper) " + suffix = " {" + } else { + prefix = " " + } + w.Writeln("%s%s(%s) C.%sResult%s", prefix, fnName, strings.Join(parameters, ", "), NameSpace, suffix) + return i, nil +} + func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, packageName string, className string, isGlobal bool) error { var errorReturn []string @@ -835,7 +998,10 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace var parameters []string var declarations []string var preOKReturn []string - + if !isGlobal { + initCallParameters = append(initCallParameters, "inst.Ref") + callParameters = append(callParameters, "inst.Ref") + } for _, param := range method.Params { param.ParamName = toGoParam(param.ParamName) tp, err := getGoType(param.ParamType, NameSpace, param.ParamClass, param.ParamName, false) @@ -933,7 +1099,6 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace } // Implementation - implmethodname := "C.CCall_" + packageName + "_" returnValues = append(returnValues, "nil") classReturnTypes = append(classReturnTypes, "error") errorReturn = append(errorReturn, "makeError(uint32(ret))") @@ -951,20 +1116,16 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace } else { w.Writeln("func (inst %s) %s(%s) %s {", className, method.MethodName, strings.Join(parameters, ", "), returnString) } - if !isGlobal { - initCallParameters = append([]string{"inst.Ref"}, initCallParameters...) - callParameters = append([]string{"inst.Ref"}, callParameters...) - implmethodname += strings.ToLower(className) + "_" - } - implmethodname += strings.ToLower(method.MethodName) w.Writelns(" ", declarations) retInst := ":" + var methodName string + if isGlobal { + methodName = "wrapper.impl." + method.MethodName + } else { + methodName = fmt.Sprintf("inst.wrapperRef.impl.%s_%s", className, method.MethodName) + } if requiresInitCall { - if isGlobal { - w.Writeln(" ret := %s(wrapper.LibraryHandle, %s)", implmethodname, strings.Join(initCallParameters, ", ")) - } else { - w.Writeln(" ret := %s(inst.wrapperRef.LibraryHandle, %s)", implmethodname, strings.Join(initCallParameters, ", ")) - } + w.Writeln(" ret := %s(%s)", methodName, strings.Join(initCallParameters, ", ")) w.Writeln(" if ret != 0 {") w.Writeln(" return %s", strings.Join(errorReturn, ", ")) @@ -973,11 +1134,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace retInst = "" } - if isGlobal { - w.Writeln(" ret %s= %s(wrapper.LibraryHandle, %s)", retInst, implmethodname, strings.Join(callParameters, ", ")) - } else { - w.Writeln(" ret %s= %s(inst.wrapperRef.LibraryHandle, %s)", retInst, implmethodname, strings.Join(callParameters, ", ")) - } + w.Writeln(" ret %s= %s(%s)", retInst, methodName, strings.Join(callParameters, ", ")) w.Writeln(" if ret != 0 {") w.Writeln(" return %s", strings.Join(errorReturn, ", "))