From 3e709519c5be7ff4ee93c096f6e0b61fc05be7dd Mon Sep 17 00:00:00 2001 From: Vijai Kumar S <2363451+vijaiaeroastro@users.noreply.github.com> Date: Mon, 25 Nov 2024 06:27:31 +0100 Subject: [PATCH] fix go bindings (#211) Co-authored-by: gangatp --- Source/buildbindingccpp.go | 1443 ++++++++++++++++++++++++++---------- Source/buildbindinggo.go | 134 +++- 2 files changed, 1162 insertions(+), 415 deletions(-) diff --git a/Source/buildbindingccpp.go b/Source/buildbindingccpp.go index 4733ff8b..fcd45493 100644 --- a/Source/buildbindingccpp.go +++ b/Source/buildbindingccpp.go @@ -60,7 +60,7 @@ func BuildBindingCExplicit(component ComponentDefinition, outputFolder string, o dynhfile.WriteCLicenseHeader(component, fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", libraryname), true) - err = buildDynamicCCPPHeader(component, dynhfile, namespace, baseName, false, false) + err = buildDynamicCCPPHeader(component, dynhfile, namespace, baseName, false, false, true) if err != nil { return err } @@ -115,7 +115,8 @@ func BuildBindingCExplicit(component ComponentDefinition, outputFolder string, o } // BuildBindingCppImplicit builds dynamic C++-bindings of a library's API in form of implicitly linked functions handles. -func BuildBindingCppImplicit(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string, ClassIdentifier string) error { +func BuildBindingCppImplicit(component ComponentDefinition, outputFolder string, outputFolderExample string, + outputFolderDocumentation string, indentString string, ClassIdentifier string) error { forceRecreation := false ExplicitLinking := false @@ -168,11 +169,21 @@ func BuildBindingCppImplicit(component ComponentDefinition, outputFolder string, log.Printf("Omitting recreation of C++-example CMakeLists-file \"%s\"", CPPCMake) } } + + if outputFolderDocumentation != "" { + + err = BuildCCPPDocumentation(component, outputFolderDocumentation, ClassIdentifier) + if err != nil { + return err + } + + } + return nil } func buildDynamicCCPPHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, - headerOnly bool, useCPPTypes bool) error { + headerOnly bool, useCPPTypes bool, includeEndGuard bool) error { sIncludeGuard := "__" + strings.ToUpper(NameSpace) + "_DYNAMICHEADER" if useCPPTypes { @@ -188,8 +199,12 @@ func buildDynamicCCPPHeader(component ComponentDefinition, w LanguageWriter, Nam w.Writeln("#include \"%s_types.h\"", BaseName) } w.Writeln("") - for _, subComponent := range(component.ImportedComponentDefinitions) { - w.Writeln("#include \"%s_types.hpp\"", subComponent.BaseName) + for _, subComponent := range component.ImportedComponentDefinitions { + if useCPPTypes { + w.Writeln("#include \"%s_types.hpp\"", subComponent.BaseName) + } else { + w.Writeln("#include \"%s_types.h\"", subComponent.BaseName) + } } w.Writeln("") @@ -256,8 +271,9 @@ func buildDynamicCCPPHeader(component ComponentDefinition, w LanguageWriter, Nam w.Writeln("") } - - w.Writeln("#endif // %s", sIncludeGuard) + if includeEndGuard { + w.Writeln("#endif // %s", sIncludeGuard) + } w.Writeln("") return nil @@ -267,14 +283,14 @@ func buildDynamicCInitTableCode(component ComponentDefinition, w LanguageWriter, global := component.Global nullPtrStr := "nullptr" - if (useStrictC) { + if useStrictC { nullPtrStr = "NULL" } w.Writeln("if (pWrapperTable == %s)", nullPtrStr) w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) w.Writeln("") - + w.Writeln("pWrapperTable->m_LibraryHandle = %s;", nullPtrStr) for i := 0; i < len(component.Classes); i++ { @@ -299,7 +315,7 @@ func buildDynamicCInitTableCode(component ComponentDefinition, w LanguageWriter, func buildDynamicCReleaseTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, initWrapperFunctionName string, useStrictC bool) error { nullPtrStr := "nullptr" - if (useStrictC) { + if useStrictC { nullPtrStr = "NULL" } @@ -323,12 +339,12 @@ func buildDynamicCReleaseTableCode(component ComponentDefinition, w LanguageWrit func writeLoadingOfMethodFromSymbolLookupMethod(w LanguageWriter, methodName string, NameSpace string, useStrictC bool) { nullPtrStr := "nullptr" - if (useStrictC) { + if useStrictC { nullPtrStr = "NULL" } w.Writeln("eLookupError = (*pLookup)(\"%s_%s\", (void**)&(pWrapperTable->m_%s));", strings.ToLower(NameSpace), strings.ToLower(methodName), methodName) - + w.Writeln("if ( (eLookupError != 0) || (pWrapperTable->m_%s == %s) )", methodName, nullPtrStr) w.Writeln(" return %s_ERROR_COULDNOTFINDLIBRARYEXPORT;", strings.ToUpper(NameSpace)) w.Writeln("") @@ -337,7 +353,7 @@ func writeLoadingOfMethodFromSymbolLookupMethod(w LanguageWriter, methodName str // WriteLoadingOfMethod the loading of a method from a library into a LanguagWriter func WriteLoadingOfMethod(class ComponentDefinitionClass, method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, useStrictC bool) { nullPtrStr := "nullptr" - if (useStrictC) { + if useStrictC { nullPtrStr = "NULL" } @@ -352,12 +368,11 @@ func WriteLoadingOfMethod(class ComponentDefinitionClass, method ComponentDefini w.Writeln("") } - func buildDynamicCLoadTableFromSymbolLookupMethodCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, useStrictC bool) error { global := component.Global nullPtrStr := "nullptr" - if (useStrictC) { + if useStrictC { nullPtrStr = "NULL" } @@ -371,8 +386,7 @@ func buildDynamicCLoadTableFromSymbolLookupMethodCode(component ComponentDefinit w.Writeln("SymbolLookupType pLookup = (SymbolLookupType)pSymbolLookupMethod;") w.Writeln("") w.Writeln("%sResult eLookupError = %s_SUCCESS;", NameSpace, strings.ToUpper(NameSpace)) - - + for i := 0; i < len(component.Classes); i++ { class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { @@ -398,7 +412,7 @@ func buildDynamicCLoadTableCode(component ComponentDefinition, w LanguageWriter, global := component.Global nullPtrStr := "nullptr" - if (useStrictC) { + if useStrictC { nullPtrStr = "NULL" } @@ -413,7 +427,7 @@ func buildDynamicCLoadTableCode(component ComponentDefinition, w LanguageWriter, w.Writeln("// Convert filename to UTF16-string") w.Writeln("int nLength = static_cast(strnlen_s(pLibraryFileName, MAX_PATH));") w.Writeln("int nBufferSize = nLength * 2 + 2;") - if (!useStrictC) { + if !useStrictC { w.Writeln("std::vector wsLibraryFileName(nBufferSize);") w.Writeln("int nResult = MultiByteToWideChar(CP_UTF8, 0, pLibraryFileName, nLength, &wsLibraryFileName[0], nBufferSize);") w.Writeln("if (nResult == 0)") @@ -432,7 +446,7 @@ func buildDynamicCLoadTableCode(component ComponentDefinition, w LanguageWriter, w.Writeln("HMODULE hLibrary = LoadLibraryW(wsLibraryFileName);") w.Writeln("free(wsLibraryFileName);") } - + w.Writeln("if (hLibrary == 0) ") w.Writeln(" return %s_ERROR_COULDNOTLOADLIBRARY;", strings.ToUpper(NameSpace)) w.Writeln("#else // _WIN32") @@ -477,7 +491,7 @@ func buildDynamicCImplementation(component ComponentDefinition, w LanguageWriter w.Writeln("#include \"%s_dynamic.h\"", BaseName) w.Writeln("#ifdef _WIN32") - if (!useStrictC) { + if !useStrictC { w.Writeln("#include ") } w.Writeln("#include ") @@ -485,7 +499,7 @@ func buildDynamicCImplementation(component ComponentDefinition, w LanguageWriter w.Writeln("#else // _WIN32") w.Writeln("#include ") w.Writeln("#include ") - w.Writeln("#endif // _WIN32") + w.Writeln("#endif // _WIN32") w.Writeln("") w.Writeln("%sResult Init%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, NameSpace, NameSpace) @@ -562,15 +576,38 @@ func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w Langua } } + return parameters, returntype, nil +} + +func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string) error { + parameters, returntype, err := getDynamicCPPMethodParameters(method, NameSpace, ClassIdentifier, ClassName) + if err != nil { + return err + } w.Writeln(" inline %s %s(%s);", returntype, method.MethodName, parameters) return nil } func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string, - implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool) error { + implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool) error { + + WASMPrefix := "" + WASMCast := "" + WASMCastp := "" + if forWASM { + WASMPrefix = "_" + WASMCast = "(uint64_t)" + WASMCastp = "(uint64_t)&" + } CMethodName := "" + // signature of the C++-binding function + parameters := "" + returntype := "void" + + callParameters := "" // parameters for call of the C-function + requiresInitCall := false initCallParameters := "" // usually used to check sizes of buffers callParameters := "" @@ -590,7 +627,7 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N if ExplicitLinking { CMethodName = fmt.Sprintf("m_pWrapper->m_WrapperTable.m_%s_%s", ClassName, method.MethodName) } else { - CMethodName = fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName)) + CMethodName = fmt.Sprintf("%s%s_%s_%s", WASMPrefix, strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName)) } callParameters = "m_pHandle" initCallParameters = "m_pHandle" @@ -621,8 +658,8 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N param := method.Params[k] variableName := getBindingCppVariableName(param) - callParameter := "" - initCallParameter := "" + callParameter := "" // parameter of the actual call of the C-function + initCallParameter := "" // parameter of an switch param.ParamPass { case "in": @@ -677,7 +714,11 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N requiresInitCall = true definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName) + if forWASM { + initCallParameter = fmt.Sprintf("%sbytesWritten%s, %s&bytesNeeded%s, 0", WASMCastp, param.ParamName, WASMCast, param.ParamName) + } else { + initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName) + } functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector buffer%s(bytesNeeded%s);", param.ParamName, param.ParamName)) @@ -695,7 +736,8 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N callParameter = fmt.Sprintf("&h%s", param.ParamName) initCallParameter = callParameter - if (param.ParamType == "optionalclass") { + CPPClass := fmt.Sprintf("%s%s%s", cppClassPrefix, ClassIdentifier, param.ParamClass) + if param.ParamType == "optionalclass" { postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("if (h%s) {", param.ParamName)) postCallCodeLines = append(postCallCodeLines, fmt.Sprintf(" p%s = std::make_shared<%s%s%s>(%s, h%s);", param.ParamName, cppClassPrefix, ClassIdentifier, param.ParamClass, makeSharedParameter, param.ParamName)) postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("} else {")) @@ -713,8 +755,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N requiresInitCall = true definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsNeeded%s = 0;", NameSpace, param.ParamName)) definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &elementsNeeded%s, nullptr", param.ParamName) + if forWASM { + initCallParameter = fmt.Sprintf("%s&elementsWritten%s, %s&elementsNeeded%s, 0", WASMCast, param.ParamName, WASMCast, param.ParamName) + } else { + initCallParameter = fmt.Sprintf("0, &elementsNeeded%s, nullptr", param.ParamName) + } functionCodeLines = append(functionCodeLines, fmt.Sprintf("%s.resize((size_t) elementsNeeded%s);", variableName, param.ParamName)) callParameter = fmt.Sprintf("elementsNeeded%s, &elementsWritten%s, %s.data()", param.ParamName, param.ParamName, variableName) @@ -738,7 +784,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N requiresInitCall = true definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName) + + if forWASM { + initCallParameter = fmt.Sprintf("%s&bytesWritten%s, %s&bytesNeeded%s, 0", WASMCast, param.ParamName, WASMCast, param.ParamName) + } else { + initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName) + } functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector buffer%s(bytesNeeded%s);", param.ParamName, param.ParamName)) @@ -768,12 +819,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N CPPClass = paramNameSpaceCPP + CPPClass makeSharedParameter = makeSharedParameter + "->m_p" + paramNameSpace + "Wrapper.get()" } - - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) - callParameter = fmt.Sprintf("&h%s", param.ParamName) + + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = (%sHandle)nullptr;", paramNameSpace, param.ParamName, NameSpace)) + callParameter = fmt.Sprintf("%s&h%s", WASMCast, param.ParamName) initCallParameter = callParameter - - if (param.ParamType == "optionalclass") { + + if param.ParamType == "optionalclass" { returnCodeLines = append(returnCodeLines, fmt.Sprintf("if (h%s) {", param.ParamName)) returnCodeLines = append(returnCodeLines, fmt.Sprintf(" return std::make_shared<%s>(%s, h%s);", CPPClass, makeSharedParameter, param.ParamName)) returnCodeLines = append(returnCodeLines, fmt.Sprintf("} else {")) @@ -835,12 +886,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N w.Writeln(" %s%s(%s)%s;", checkErrorCodeBegin, CMethodName, callParameters, checkErrorCodeEnd) w.Writelns(" ", postCallCodeLines) - if (len(implementationLines) >0) { + if len(implementationLines) > 0 { w.Writeln(" ") w.Writelns(" ", implementationLines) } - if (len(returnCodeLines) >0) { + if len(returnCodeLines) > 0 { w.Writeln(" ") w.Writelns(" ", returnCodeLines) } @@ -903,7 +954,6 @@ func writeDynamicCppBaseClassMethods(component ComponentDefinition, baseClass Co return nil } - func buildBindingCPPAllForwardDeclarations(component ComponentDefinition, w LanguageWriter, NameSpace string, cppClassPrefix string, ClassIdentifier string) { w.Writeln("/*************************************************************************************************************************") w.Writeln(" Forward Declaration of all classes") @@ -914,7 +964,7 @@ func buildBindingCPPAllForwardDeclarations(component ComponentDefinition, w Lang className := cppClassPrefix + ClassIdentifier + class.ClassName w.Writeln("class %s;", className) } - if (strings.Compare(ClassIdentifier, NameSpace) != 0) { + if strings.Compare(ClassIdentifier, NameSpace) != 0 { w.Writeln("") w.Writeln("/*************************************************************************************************************************") w.Writeln(" Declaration of deprecated class types") @@ -937,8 +987,8 @@ func buildBindingCPPAllForwardDeclarations(component ComponentDefinition, w Lang className := cppClassPrefix + ClassIdentifier + class.ClassName w.Writeln("typedef std::shared_ptr<%s> P%s%s;", className, ClassIdentifier, class.ClassName) } - - if (strings.Compare(ClassIdentifier, NameSpace) != 0) { + + if strings.Compare(ClassIdentifier, NameSpace) != 0 { w.Writeln("") w.Writeln("/*************************************************************************************************************************") w.Writeln(" Declaration of deprecated shared pointer types") @@ -986,21 +1036,73 @@ func writeCPPInputVector(w LanguageWriter, NameSpace string, ClassIdentifier str w.Writeln(" }") w.Writeln(" ") w.Writeln("};") - w.Writeln("") - if (strings.Compare(ClassIdentifier, NameSpace) != 0) { + if strings.Compare(ClassIdentifier, NameSpace) != 0 { + w.Writeln("") w.Writeln("// declare deprecated class name") w.Writeln("template") w.Writeln("using C%sInputVector = C%sInputVector;", NameSpace, ClassIdentifier) } - return nil +} + +func writeWrapperLifeTimeHandling(w LanguageWriter, cppClassPrefix string, ClassIdentifier string, ExplicitLinking bool) { + if ExplicitLinking { + w.Writeln(" explicit %s%sWrapper(void* pSymbolLookupMethod)", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" CheckError(nullptr, initWrapperTable(&m_WrapperTable));") + w.Writeln(" CheckError(nullptr, loadWrapperTableFromSymbolLookupMethod(&m_WrapperTable, pSymbolLookupMethod));") + w.Writeln(" ") + w.Writeln(" CheckError(nullptr, checkBinaryVersion());") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" explicit %s%sWrapper(const std::string &sFileName)", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" CheckError(nullptr, initWrapperTable(&m_WrapperTable));") + w.Writeln(" CheckError(nullptr, loadWrapperTable(&m_WrapperTable, sFileName.c_str()));") + w.Writeln(" ") + w.Writeln(" CheckError(nullptr, checkBinaryVersion());") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" static P%sWrapper loadLibrary(const std::string &sFileName)", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>(sFileName);", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" static P%sWrapper loadLibraryFromSymbolLookupMethod(void* pSymbolLookupMethod)", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>(pSymbolLookupMethod);", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" releaseWrapperTable(&m_WrapperTable);") + w.Writeln(" }") + } else { + w.Writeln(" %s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" }") + + w.Writeln(" static inline P%sWrapper loadLibrary()", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>();", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + } } func decomposeParamClassNameCPP(paramClassName string) (string, string, error) { paramNameSpace, paramClassName, err := decomposeParamClassName(paramClassName) - if (err != nil) { + if err != nil { return "", "", err } - if (len(paramNameSpace) >0 ) { + if len(paramNameSpace) > 0 { paramNameSpace = paramNameSpace + "::" } return paramNameSpace, paramClassName, err @@ -1034,15 +1136,15 @@ func getBindingCppParamType(paramType string, paramClass string, NameSpace strin } return fmt.Sprintf("std::vector<%s>", cppBasicType) case "structarray": - typeName := paramNameSpace + "s"+paramClassName + typeName := paramNameSpace + "s" + paramClassName if isInput { return fmt.Sprintf("C%sInputVector<%s>", ClassIdentifier, typeName) } return fmt.Sprintf("std::vector<%s>", typeName) case "enum": - return fmt.Sprintf(paramNameSpace + "e"+paramClassName) + return fmt.Sprintf(paramNameSpace + "e" + paramClassName) case "struct": - return fmt.Sprintf(paramNameSpace + "s"+paramClassName) + return fmt.Sprintf(paramNameSpace + "s" + paramClassName) case "class", "optionalclass": if isInput { return fmt.Sprintf("classParam<%s%s%s%s>", paramNameSpace, cppClassPrefix, ClassIdentifier, paramClassName) @@ -1086,42 +1188,16 @@ func getBindingCppVariableName(param ComponentDefinitionParam) string { return "" } - -func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, ClassIdentifier string, ExplicitLinking bool) error { - useCPPTypes := true - - global := component.Global - - cppClassPrefix := "C" - baseClass := component.baseClass() - cppBaseClassName := cppClassPrefix + ClassIdentifier + baseClass.ClassName - - sIncludeGuard := ""; - - if ExplicitLinking { - sIncludeGuard = "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_DYNAMIC" - } else { - sIncludeGuard = "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_IMPLICIT" - } - - if useCPPTypes { - sIncludeGuard += "_CPP" - } - w.Writeln("#ifndef %s", sIncludeGuard) - w.Writeln("#define %s", sIncludeGuard) - w.Writeln("") - - w.Writeln("#include \"%s_types.hpp\"", BaseName) - - if ExplicitLinking { - w.Writeln("#include \"%s_dynamic.h\"", BaseName) - } else { - w.Writeln("#include \"%s_abi.hpp\"", BaseName) - } - - w.Writeln("") - for _, subComponent := range(component.ImportedComponentDefinitions) { - w.Writeln("#include \"%s_dynamic.hpp\"", subComponent.BaseName) +func getCPPInheritanceSpecifier(component ComponentDefinition, class ComponentDefinitionClass, cppClassPrefix string, ClassIdentifier string) (string, string) { + cppParentClassName := "" + inheritanceSpecifier := "" + if !component.isBaseClass(class) { + if class.ParentClass == "" { + cppParentClassName = cppClassPrefix + ClassIdentifier + component.Global.BaseClassName + } else { + cppParentClassName = cppClassPrefix + ClassIdentifier + class.ParentClass + } + inheritanceSpecifier = fmt.Sprintf(": public %s ", cppParentClassName) } w.Writeln("") @@ -1141,7 +1217,6 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s buildBindingCPPAllForwardDeclarations(component, w, NameSpace, cppClassPrefix, ClassIdentifier) - w.Writeln("") w.Writeln("/*************************************************************************************************************************") w.Writeln(" classParam Definition") @@ -1211,7 +1286,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln(" {") w.Writeln(" return m_errorMessage.c_str();") w.Writeln(" }") - w.Writeln(""); + w.Writeln("") w.Writeln(" const char* getErrorMessage() const noexcept") w.Writeln(" {") w.Writeln(" return m_originalErrorMessage.c_str();") @@ -1221,22 +1296,22 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln(" {") w.Writeln(" switch(getErrorCode()) {") w.Writeln(" case %s_SUCCESS: return \"SUCCESS\";", strings.ToUpper(NameSpace)) - for _, errorDef := range(component.Errors.Errors) { + for _, errorDef := range errors.Errors { w.Writeln(" case %s_ERROR_%s: return \"%s\";", strings.ToUpper(NameSpace), errorDef.Name, errorDef.Name) } w.Writeln(" }") - w.Writeln(" return \"UNKNOWN\";"); + w.Writeln(" return \"UNKNOWN\";") w.Writeln(" }") w.Writeln("") w.Writeln(" const char* getErrorDescription() const noexcept") w.Writeln(" {") w.Writeln(" switch(getErrorCode()) {") w.Writeln(" case %s_SUCCESS: return \"success\";", strings.ToUpper(NameSpace)) - for _, errorDef := range(component.Errors.Errors) { + for _, errorDef := range errors.Errors { w.Writeln(" case %s_ERROR_%s: return \"%s\";", strings.ToUpper(NameSpace), errorDef.Name, errorDef.Description) } w.Writeln(" }") - w.Writeln(" return \"unknown error\";"); + w.Writeln(" return \"unknown error\";") w.Writeln(" }") w.Writeln("") @@ -1262,99 +1337,228 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s } w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %s%sWrapper ", cppClassPrefix, ClassIdentifier) - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("class %s%sWrapper {", cppClassPrefix, ClassIdentifier) - w.Writeln("public:") - w.Writeln(" ") - - if ExplicitLinking { - w.Writeln(" explicit %s%sWrapper(void* pSymbolLookupMethod)", cppClassPrefix, ClassIdentifier) - w.Writeln(" {") - w.Writeln(" CheckError(nullptr, initWrapperTable(&m_WrapperTable));") - w.Writeln(" CheckError(nullptr, loadWrapperTableFromSymbolLookupMethod(&m_WrapperTable, pSymbolLookupMethod));") - w.Writeln(" ") - w.Writeln(" CheckError(nullptr, checkBinaryVersion());") - w.Writeln(" }") - w.Writeln(" ") + w.Writeln("inline %sResult %s%sWrapper::loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln("{") + w.AddIndentationLevel(1) + buildDynamicCLoadTableCode(component, w, NameSpace, BaseName, false) + w.AddIndentationLevel(-1) + w.Writeln("}") - w.Writeln(" explicit %s%sWrapper(const std::string &sFileName)", cppClassPrefix, ClassIdentifier) - w.Writeln(" {") - w.Writeln(" CheckError(nullptr, initWrapperTable(&m_WrapperTable));") - w.Writeln(" CheckError(nullptr, loadWrapperTable(&m_WrapperTable, sFileName.c_str()));") - w.Writeln(" ") - w.Writeln(" CheckError(nullptr, checkBinaryVersion());") - w.Writeln(" }") - w.Writeln(" ") + w.Writeln("") + w.Writeln("inline %sResult %s%sWrapper::loadWrapperTableFromSymbolLookupMethod(s%sDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln("{") + w.AddIndentationLevel(1) + buildDynamicCLoadTableFromSymbolLookupMethodCode(component, w, NameSpace, BaseName, false) + w.AddIndentationLevel(-1) + w.Writeln("}") + w.Writeln("") +} - w.Writeln(" static P%sWrapper loadLibrary(const std::string &sFileName)", ClassIdentifier) - w.Writeln(" {") - w.Writeln(" return std::make_shared<%s%sWrapper>(sFileName);", cppClassPrefix, ClassIdentifier) - w.Writeln(" }") - w.Writeln(" ") +func writeClassDeclarations(w LanguageWriter, component ComponentDefinition, cppClassPrefix string, ClassIdentifier string, NameSpace string, BaseName string) error { + baseClass := component.baseClass() + for _, class := range component.Classes { + cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName + cppParentClassName, inheritanceSpecifier := getCPPInheritanceSpecifier(component, class, cppClassPrefix, ClassIdentifier) - w.Writeln(" static P%sWrapper loadLibraryFromSymbolLookupMethod(void* pSymbolLookupMethod)", ClassIdentifier) - w.Writeln(" {") - w.Writeln(" return std::make_shared<%s%sWrapper>(pSymbolLookupMethod);", cppClassPrefix, ClassIdentifier) - w.Writeln(" }") w.Writeln(" ") - - w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) - w.Writeln(" {") - w.Writeln(" releaseWrapperTable(&m_WrapperTable);") - w.Writeln(" }") - } else { - w.Writeln(" %s%sWrapper()", cppClassPrefix, ClassIdentifier) - w.Writeln(" {") - w.Writeln(" }") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class %s ", cppClassName) + w.Writeln("**************************************************************************************************************************/") + w.Writeln("class %s %s{", cppClassName, inheritanceSpecifier) + w.Writeln("public:") w.Writeln(" ") + if !component.isBaseClass(class) { + w.Writeln(" /**") + w.Writeln(" * %s::%s - Constructor for %s class.", cppClassName, cppClassName, class.ClassName) + w.Writeln(" */") + w.Writeln(" %s(%s%sWrapper* pWrapper, %sHandle pHandle)", cppClassName, cppClassPrefix, ClassIdentifier, NameSpace) + if cppParentClassName != "" { + w.Writeln(" : %s(pWrapper, pHandle)", cppParentClassName) + } + w.Writeln(" {") + w.Writeln(" }") + w.Writeln(" ") + } else { + err := writeDynamicCppBaseClassMethods(component, baseClass, w, NameSpace, BaseName, cppClassPrefix, ClassIdentifier) + if err != nil { + return err + } + } - w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) - w.Writeln(" {") - w.Writeln(" }") - - w.Writeln(" static inline P%sWrapper loadLibrary()", ClassIdentifier) - w.Writeln(" {") - w.Writeln(" return std::make_shared<%s%sWrapper>();", cppClassPrefix, ClassIdentifier) - w.Writeln(" }") + for _, method := range class.Methods { + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) + if err != nil { + return err + } + } + w.Writeln("};") } - - w.Writeln(" ") - w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace) - w.Writeln("") - - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] + return nil +} - err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, "Wrapper") - if err != nil { - return err - } +func writePolymorphicFactoryImplementation(w LanguageWriter, component ComponentDefinition, NameSpace string, cppClassPrefix string, ClassIdentifier string, ExplicitLinking bool, forWASM bool) { + WASMPrefix := "" + WASMCast := "" + WASMCastp := "" + if forWASM { + WASMPrefix = "_" + WASMCast = "(uint64_t)" + WASMCastp = "(uint64_t)&" } w.Writeln("") - w.Writeln("private:") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" RTTI: Polymorphic Factory implementation") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("") + w.Writeln("/**") + w.Writeln("* IMPORTANT: PolymorphicFactory method should not be used by application directly.") + w.Writeln("* It's designed to be used on %sHandle object only once.", NameSpace) + w.Writeln("* If it's used on any existing object as a form of dynamic cast then") + w.Writeln("* %s%sWrapper::AcquireInstance(C%s object) must be called after instantiating new object.", cppClassPrefix, ClassIdentifier, component.Global.BaseClassName) + w.Writeln("* This is important to keep reference count matching between application and library sides.") + w.Writeln("*/") + w.Writeln("inline C%s* %s%sWrapper::polymorphicFactory(%sHandle pHandle)", component.Global.BaseClassName, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln("{") + w.Writeln(" %s_uint64 resultClassTypeId = 0;", NameSpace) if ExplicitLinking { - w.Writeln(" s%sDynamicWrapperTable m_WrapperTable;", NameSpace) + w.Writeln(" CheckError(nullptr, m_WrapperTable.m_%s_%s(pHandle, &resultClassTypeId));", component.Global.BaseClassName, component.Global.ClassTypeIdMethod) + } else { + w.Writeln(" CheckError(nullptr, %s%s_%s_%s(%spHandle, %s&resultClassTypeId));", WASMPrefix, strings.ToLower(NameSpace), strings.ToLower(component.Global.BaseClassName), strings.ToLower(component.Global.ClassTypeIdMethod), WASMCastp, WASMCast) } - - if len(component.ImportedComponentDefinitions) > 0 { - w.Writeln(" // Injected Components") - for _, subComponent := range(component.ImportedComponentDefinitions) { - subNameSpace := subComponent.NameSpace - w.Writeln(" %s::PWrapper m_p%sWrapper;", subNameSpace, subNameSpace) - } - w.Writeln("") + w.Writeln(" switch(resultClassTypeId) {") + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + classTypeId, chashHashString := class.classTypeId(NameSpace) + w.Writeln(" case 0x%016XUL: return new C%s(this, pHandle); break; // First 64 bits of SHA1 of a string: \"%s\"", classTypeId, class.ClassName, chashHashString) } - - - w.Writeln(" ") - w.Writeln(" %sResult checkBinaryVersion()", NameSpace) - w.Writeln(" {") - w.Writeln(" %s_uint32 nMajor, nMinor, nMicro;", NameSpace) - w.Writeln(" %s(nMajor, nMinor, nMicro);", global.VersionMethod) + w.Writeln(" }") + + w.Writeln(" return new C%s(this, pHandle);", component.Global.BaseClassName) + w.Writeln("}") +} + +func writeCheckErrorImplementation(w LanguageWriter, ErrorMethodName string, ClassIdentifier string, cppBaseClassName string, NameSpace string) { + w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace) + w.Writeln(" {") + w.Writeln(" if (nResult != 0) {") + w.Writeln(" std::string sErrorMessage;") + w.Writeln(" if (pBaseClass != nullptr) {") + w.Writeln(" %s(pBaseClass, sErrorMessage);", ErrorMethodName) + w.Writeln(" }") + w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" ") +} + +func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, ClassIdentifier string, ExplicitLinking bool) error { + useCPPTypes := true + + global := component.Global + + cppClassPrefix := "C" + baseClass := component.baseClass() + cppBaseClassName := cppClassPrefix + ClassIdentifier + baseClass.ClassName + + sIncludeGuard := "" + + if ExplicitLinking { + sIncludeGuard = "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_DYNAMIC" + } else { + sIncludeGuard = "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_IMPLICIT" + } + + if useCPPTypes { + sIncludeGuard += "_CPP" + } + w.Writeln("#ifndef %s", sIncludeGuard) + w.Writeln("#define %s", sIncludeGuard) + w.Writeln("") + + w.Writeln("#include \"%s_types.hpp\"", BaseName) + + if ExplicitLinking { + w.Writeln("#include \"%s_dynamic.h\"", BaseName) + } else { + w.Writeln("#include \"%s_abi.hpp\"", BaseName) + } + + w.Writeln("") + for _, subComponent := range component.ImportedComponentDefinitions { + w.Writeln("#include \"%s_dynamic.hpp\"", subComponent.BaseName) + } + w.Writeln("") + + w.Writeln("#ifdef _WIN32") + w.Writeln("#include ") + w.Writeln("#else // _WIN32") + w.Writeln("#include ") + w.Writeln("#endif // _WIN32") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("") + + w.Writeln("namespace %s {", NameSpace) + w.Writeln("") + + buildBindingCPPAllForwardDeclarations(component, w, NameSpace, cppClassPrefix, ClassIdentifier) + + writeClassParamDefinition(w, NameSpace) + w.Writeln("") + + writeExceptionClass(w, NameSpace, component.Errors) + w.Writeln("") + + writeCPPInputVector(w, NameSpace, ClassIdentifier) + w.Writeln("") + + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class %s%sWrapper ", cppClassPrefix, ClassIdentifier) + w.Writeln("**************************************************************************************************************************/") + + w.Writeln("class %s%sWrapper {", cppClassPrefix, ClassIdentifier) + w.Writeln("public:") + w.Writeln(" ") + + writeWrapperLifeTimeHandling(w, cppClassPrefix, ClassIdentifier, ExplicitLinking) + + w.Writeln(" ") + w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace) + w.Writeln("") + + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, "Wrapper") + if err != nil { + return err + } + } + + w.Writeln("") + w.Writeln("private:") + if ExplicitLinking { + w.Writeln(" s%sDynamicWrapperTable m_WrapperTable;", NameSpace) + } + + if len(component.ImportedComponentDefinitions) > 0 { + w.Writeln(" // Injected Components") + for _, subComponent := range component.ImportedComponentDefinitions { + subNameSpace := subComponent.NameSpace + w.Writeln(" %s::PWrapper m_p%sWrapper;", subNameSpace, subNameSpace) + } + w.Writeln("") + } + + w.Writeln(" ") + w.Writeln(" %sResult checkBinaryVersion()", NameSpace) + w.Writeln(" {") + w.Writeln(" %s_uint32 nMajor, nMinor, nMicro;", NameSpace) + w.Writeln(" %s(nMajor, nMinor, nMicro);", global.VersionMethod) if minorVersion(component.Version) > 0 { w.Writeln(" if ( (nMajor != %s_VERSION_MAJOR) || (nMinor < %s_VERSION_MINOR) ) {", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace)) } else { @@ -1365,91 +1569,691 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln(" return %s_SUCCESS;", strings.ToUpper(NameSpace)) w.Writeln(" }") - if ExplicitLinking { - w.Writeln(" %sResult initWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) - w.Writeln(" %sResult releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) - w.Writeln(" %sResult loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace) - w.Writeln(" %sResult loadWrapperTableFromSymbolLookupMethod(s%sDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod);", NameSpace, NameSpace) - } - w.Writeln("") + if ExplicitLinking { + w.Writeln(" %sResult initWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) + w.Writeln(" %sResult releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) + w.Writeln(" %sResult loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace) + w.Writeln(" %sResult loadWrapperTableFromSymbolLookupMethod(s%sDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod);", NameSpace, NameSpace) + } + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName + w.Writeln(" friend class %s;", cppClassName) + } + + w.Writeln("") + w.Writeln("};") + w.Writeln("") + + err := writeClassDeclarations(w, component, cppClassPrefix, ClassIdentifier, NameSpace, BaseName) + if err != nil { + return err + } + + writePolymorphicFactoryImplementation(w, component, NameSpace, cppClassPrefix, ClassIdentifier, ExplicitLinking, false) + + for _, method := range component.Global.Methods { + isSpecialFunction, err := CheckHeaderSpecialFunction(method, component.Global) + if err != nil { + return err + } + + implementationLines := make([]string, 0) + if isSpecialFunction == eSpecialMethodInjection { + implementationLines = append(implementationLines, "bool bNameSpaceFound = false;") + sParamName := "s" + method.Params[0].ParamName + for _, subComponent := range component.ImportedComponentDefinitions { + theNameSpace := subComponent.NameSpace + implementationLines = append(implementationLines, fmt.Sprintf("if (%s == \"%s\") {", sParamName, theNameSpace)) + implementationLines = append(implementationLines, fmt.Sprintf(" if (m_p%sWrapper != nullptr) {", theNameSpace)) + implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Library with namespace \" + %s + \" is already registered.\");", NameSpace, strings.ToUpper(NameSpace), sParamName)) + implementationLines = append(implementationLines, fmt.Sprintf(" }")) + + implementationLines = append(implementationLines, fmt.Sprintf(" m_p%sWrapper = %s::CWrapper::loadLibraryFromSymbolLookupMethod(p%s);", theNameSpace, theNameSpace, method.Params[1].ParamName)) + implementationLines = append(implementationLines, fmt.Sprintf(" bNameSpaceFound = true;")) + implementationLines = append(implementationLines, fmt.Sprintf("}")) + } + implementationLines = append(implementationLines, "if (!bNameSpaceFound)") + implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName)) + } + + err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking) + if err != nil { + return err + } + + } + + w.Writeln(" ") + w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace) + w.Writeln(" {") + w.Writeln(" if (nResult != 0) {") + w.Writeln(" std::string sErrorMessage;") + w.Writeln(" if (pBaseClass != nullptr) {") + w.Writeln(" %s(pBaseClass, sErrorMessage);", component.Global.ErrorMethod) + w.Writeln(" }") + w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln("") + + if ExplicitLinking { + w.Writeln(" inline %sResult %s%sWrapper::initWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" {") + + w.AddIndentationLevel(2) + buildDynamicCInitTableCode(component, w, NameSpace, BaseName, false) + w.AddIndentationLevel(-2) + + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" inline %sResult %s%sWrapper::releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" {") + + w.AddIndentationLevel(2) + buildDynamicCReleaseTableCode(component, w, NameSpace, BaseName, "initWrapperTable", false) + w.AddIndentationLevel(-2) + + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" inline %sResult %s%sWrapper::loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" {") + + w.AddIndentationLevel(2) + buildDynamicCLoadTableCode(component, w, NameSpace, BaseName, false) + w.AddIndentationLevel(-2) + + w.Writeln(" }") + + w.Writeln("") + w.Writeln(" inline %sResult %s%sWrapper::loadWrapperTableFromSymbolLookupMethod(s%sDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln("{") + + w.AddIndentationLevel(2) + buildDynamicCLoadTableFromSymbolLookupMethodCode(component, w, NameSpace, BaseName, false) + w.AddIndentationLevel(-2) + + w.Writeln("}") + w.Writeln("") + + w.Writeln(" ") + } + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + cppClassName := cppClassPrefix + class.ClassName + w.Writeln(" ") + w.Writeln(" /**") + w.Writeln(" * Method definitions for class %s", cppClassName) + w.Writeln(" */") + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false) + if err != nil { + return err + } + } + } + + w.Writeln("") + + w.Writeln("} // namespace %s", NameSpace) + w.Writeln("") + + w.Writeln("#endif // %s", sIncludeGuard) + w.Writeln("") + + return nil +} + +// BuildBindingCppExplicit builds headeronly C++-bindings of a library's API in form of expliclty loaded function handles. +func BuildBindingCppExplicit(component ComponentDefinition, outputFolder string, outputFolderExample string, + indentString string, ClassIdentifier string) error { + forceRecreation := false + ExplicitLinking := true + namespace := component.NameSpace + libraryname := component.LibraryName + baseName := component.BaseName + + DynamicCHeader := path.Join(outputFolder, baseName+"_dynamic.h") + log.Printf("Creating \"%s\"", DynamicCHeader) + dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) + if err != nil { + return err + } + dynhfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), + true) + err = buildDynamicCCPPHeader(component, dynhfile, namespace, baseName, true, true, true) + if err != nil { + return err + } + + DynamicCppHeader := path.Join(outputFolder, baseName+"_dynamic.hpp") + log.Printf("Creating \"%s\"", DynamicCppHeader) + dynhppfile, err := CreateLanguageFile(DynamicCppHeader, indentString) + if err != nil { + return err + } + dynhppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), + true) + err = buildCppHeader(component, dynhppfile, namespace, baseName, ClassIdentifier, ExplicitLinking) + if err != nil { + return err + } + + if len(outputFolderExample) > 0 { + DynamicCPPExample := path.Join(outputFolderExample, namespace+"_example"+".cpp") + if forceRecreation || !FileExists(DynamicCPPExample) { + log.Printf("Creating \"%s\"", DynamicCPPExample) + dyncppexamplefile, err := CreateLanguageFile(DynamicCPPExample, indentString) + if err != nil { + return err + } + dyncppexamplefile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++ application that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), + true) + buildDynamicCppExample(component, dyncppexamplefile, outputFolder, ClassIdentifier, ExplicitLinking) + } else { + log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPExample) + } + + DynamicCPPCMake := path.Join(outputFolderExample, "CMakeLists.txt") + if forceRecreation || !FileExists(DynamicCPPCMake) { + log.Printf("Creating \"%s\"", DynamicCPPCMake) + dyncppcmake, err := CreateLanguageFile(DynamicCPPCMake, " ") + if err != nil { + return err + } + dyncppcmake.WriteCMakeLicenseHeader(component, + fmt.Sprintf("This is an autogenerated CMake Project that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), + true) + buildCppDynamicExampleCMake(component, dyncppcmake, outputFolder, outputFolderExample, ExplicitLinking) + } else { + log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPCMake) + } + } + + if outputFolderDocumentation != "" { + + err = BuildCCPPDocumentation(component, outputFolderDocumentation, ClassIdentifier) + if err != nil { + return err + } + + } + + return nil +} + +// BuildBindingCppwasmtimeHost builds headeronly C++-bindings of a library's API in form of explicitly loaded function handles. +// it maps all C-functions to functions objects that can be linked into a wasmtime module +func BuildBindingCppwasmtimeHost(component ComponentDefinition, outputFolder string, outputFolderExample string, + outputFolderDocumentation string, indentString string, ClassIdentifier string) error { + namespace := component.NameSpace + libraryname := component.LibraryName + baseName := component.BaseName + + DynamicCppHeader := path.Join(outputFolder, baseName+"_wasm_host.hpp") + log.Printf("Creating \"%s\"", DynamicCppHeader) + wasmhosthppfile, err := CreateLanguageFile(DynamicCppHeader, indentString) + if err != nil { + return err + } + wasmhosthppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s.", libraryname)+ + fmt.Sprintf("It loads the functions exported by the component and wraps them with C++ function objects\nthat can be linked into a wasmtime module."), + true) + err = buildCppwasmHostHeader(component, wasmhosthppfile, namespace, baseName, ClassIdentifier) + if err != nil { + return err + } + + // TODO: examples and documentation + return nil +} + +// BuildBindingCppwasmtimeGuest builds headeronly C++-bindings of a library's API in form of implicitly linked functions. +// It imports the component's functions exported by the host and creates a C++ wrapper\n that can be used within a wasmtime module like the regular C++ bindings of that component. +func BuildBindingCppwasmtimeGuest(component ComponentDefinition, outputFolder string, outputFolderExample string, + outputFolderDocumentation string, indentString string, ClassIdentifier string) error { + + namespace := component.NameSpace + libraryname := component.LibraryName + baseName := component.BaseName + + WASMGuestCppHeader := path.Join(outputFolder, baseName+"_wasm_guest.hpp") + log.Printf("Creating \"%s\"", WASMGuestCppHeader) + wasmguesthppfile, err := CreateLanguageFile(WASMGuestCppHeader, indentString) + if err != nil { + return err + } + wasmguesthppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s.", libraryname)+ + fmt.Sprintf("It imports the component's functions exported by the host and creates a C++ wrapper\n that can be used within a wasmtime module like the regular C++ bindings of that component."), + true) + err = buildCppwasmGuestHeader(component, wasmguesthppfile, namespace, baseName, ClassIdentifier) + if err != nil { + return err + } + + // TODO: examples and documentation + return nil +} + +func cParamIsPointer(cParam CParameter) bool { + if len(cParam.ParamType) == 0 { + return false + } + return cParam.ParamType[len(cParam.ParamType)-1:] == "*" +} + +func writeWasmtimeImport(w LanguageWriter, NameSpace string, method ComponentDefinitionMethod, methodName string, className string) error { + wasmtimeParams := "" + first := true + + var allCParams []CParameter + if className != "" { + allCParams = make([]CParameter, 1) + allCParams[0].ParamName = "hHandle" + allCParams[0].ParamType = NameSpace + "Handle" + } + + for _, param := range method.Params { + cParams, err := generateCCPPParameter(param, className, method.MethodName, NameSpace, false) + if err != nil { + return err + } + allCParams = append(allCParams, cParams...) + } + for i := 0; i < len(allCParams); i++ { + if !first { + wasmtimeParams += ", " + } + first = false + wasmtimeParams += "uint64_t" + } + + if className != "" { + className = className + "_" + } + w.Writeln(" __attribute__((import_module(\"\"), import_name(\"%s\"))) int32_t %s(%s);", methodName, methodName, wasmtimeParams) + return nil +} + +func writeWasmtimeLambda(w LanguageWriter, NameSpace string, method ComponentDefinitionMethod, methodName string, className string) error { + wasmtimeParams := "" + cParameters := "" + var lines []string + first := true + + var allCParams []CParameter + if className != "" { + allCParams = make([]CParameter, 1) + allCParams[0].ParamName = "hHandle" + allCParams[0].ParamType = NameSpace + "Handle" + } + + for _, param := range method.Params { + cParams, err := generateCCPPParameter(param, className, method.MethodName, NameSpace, false) + if err != nil { + return err + } + allCParams = append(allCParams, cParams...) + } + for _, cParam := range allCParams { + if !first { + wasmtimeParams += ", " + cParameters += ", " + } + first = false + wasmtimeParams += "uint64_t w" + cParam.ParamName + cParameters += cParam.ParamName + + pointerString := "" + if !cParamIsPointer(cParam) { + pointerString = "*" + } + // ensure memory access does not go outside of WASM linear memory + lines = append(lines, fmt.Sprintf("if (w%s + sizeof(%s) >= nMemorySize)", cParam.ParamName, cParam.ParamType)) + lines = append(lines, fmt.Sprintf(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace))) + lines = append(lines, fmt.Sprintf("%s %s = %s( (%s %s)(_pData + w%s) );", cParam.ParamType, cParam.ParamName, pointerString, cParam.ParamType, pointerString, cParam.ParamName)) + if cParamIsPointer(cParam) { + // a nullptr in the WASM module is conveyed to the host as a 0 offset in WASM linear memory + lines = append(lines, fmt.Sprintf("if (w%s == 0)", cParam.ParamName)) + lines = append(lines, fmt.Sprintf("{")) + lines = append(lines, fmt.Sprintf(" %s = nullptr;", cParam.ParamName)) + lines = append(lines, fmt.Sprintf("}")) + } + } + + w.Writeln(" auto %s = [this, &store](%s)", methodName, wasmtimeParams) + w.Writeln(" {") + w.Writeln(" auto data = this->m_pMemory->data(store);") + w.Writeln(" uint8_t* _pData = data.data();") + w.Writeln(" const uint64_t nMemorySize = data.size();") + w.Writeln(" ") + + w.Writelns(" ", lines) + + if className != "" { + className = className + "_" + } + w.Writeln(" %sResult result = this->m_WrapperTable.m_%s%s(%s);", NameSpace, className, method.MethodName, cParameters) + + w.Writeln(" return result;") + w.Writeln(" };") + w.Writeln(" ") + return nil +} + +func buildCppwasmHostHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, ClassIdentifier string) error { + cppClassPrefix := "C" + + sIncludeGuard := "__" + strings.ToUpper(NameSpace) + "_CPPWASMTIMEHOSTHEADER_DYNAMIC_CPP" + + w.Writeln("#ifndef %s", sIncludeGuard) + w.Writeln("#define %s", sIncludeGuard) + w.Writeln("") + + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("") + w.Writeln("#include ") + w.Writeln("") + w.Writeln("#ifdef _WIN32") + w.Writeln("#include ") + w.Writeln("#else // _WIN32") + w.Writeln("#include ") + w.Writeln("#endif // _WIN32") + w.Writeln("") + + w.Writeln("#include \"%s_dynamic.h\"", BaseName) + + if len(component.ImportedComponentDefinitions) > 0 { + return fmt.Errorf("C++ wasmtime bindings to not support imported components yet") + } + w.Writeln("") + + w.Writeln("namespace %sWASM {", NameSpace) + w.Writeln("") + + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Declaration of shared pointer types") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("class %s%sWrapper;", cppClassPrefix, ClassIdentifier) + w.Writeln("typedef std::shared_ptr<%s%sWrapper> P%sWrapper;", cppClassPrefix, ClassIdentifier, ClassIdentifier) + + writeExceptionClass(w, NameSpace, component.Errors) + + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class %s%sWrapper ", cppClassPrefix, ClassIdentifier) + w.Writeln("**************************************************************************************************************************/") + + w.Writeln("class %s%sWrapper {", cppClassPrefix, ClassIdentifier) + w.Writeln("public:") + w.Writeln(" ") + + w.Writeln(" explicit %s%sWrapper(void* pSymbolLookupMethod)", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" CheckError(initWrapperTable(&m_WrapperTable));") + w.Writeln(" CheckError(loadWrapperTableFromSymbolLookupMethod(&m_WrapperTable, pSymbolLookupMethod));") + w.Writeln(" ") + // w.Writeln(" CheckError(checkBinaryVersion());") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" explicit %s%sWrapper(const std::string &sFileName)", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" CheckError(initWrapperTable(&m_WrapperTable));") + w.Writeln(" CheckError(loadWrapperTable(&m_WrapperTable, sFileName.c_str()));") + w.Writeln(" ") + // w.Writeln(" CheckError(checkBinaryVersion());") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" static P%sWrapper loadLibrary(const std::string &sFileName)", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>(sFileName);", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" static P%sWrapper loadLibraryFromSymbolLookupMethod(void* pSymbolLookupMethod)", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>(pSymbolLookupMethod);", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" releaseWrapperTable(&m_WrapperTable);") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" inline void CheckError(%sResult nResult)", NameSpace) + w.Writeln(" {") + w.Writeln(" if (nResult != 0) {") + w.Writeln(" std::string sErrorMessage;") + w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" void setWASMMemory(wasmtime::Memory* pMemory)") + w.Writeln(" {") + w.Writeln(" m_pMemory = pMemory;") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" void linkComponentToWASM(wasmtime::Linker& linker, wasmtime::Store& store);") + w.Writeln(" ") + + w.Writeln("private:") + w.Writeln(" s%sDynamicWrapperTable m_WrapperTable;", NameSpace) + w.Writeln(" wasmtime::Memory* m_pMemory;") + w.Writeln(" ") + + // writeCheckBinaryVersion(w, NameSpace, component) + + w.Writeln(" ") + w.Writeln(" %sResult initWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) + w.Writeln(" %sResult releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) + w.Writeln(" %sResult loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace) + w.Writeln(" %sResult loadWrapperTableFromSymbolLookupMethod(s%sDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod);", NameSpace, NameSpace) + + w.Writeln("};") + w.Writeln("") + + writeWrapperTableHandling(w, component, NameSpace, cppClassPrefix, ClassIdentifier, BaseName) + + w.Writeln("") + + w.Writeln("inline void %s%sWrapper::linkComponentToWASM(wasmtime::Linker& linker, wasmtime::Store& store)", cppClassPrefix, ClassIdentifier) + w.Writeln("{") + var functionNames []string + + for j := 0; j < len(component.Global.Methods); j++ { + method := component.Global.Methods[j] + methodName := "_" + strings.ToLower(NameSpace) + "_" + strings.ToLower(method.MethodName) + + err := writeWasmtimeLambda(w, NameSpace, method, methodName, "") + if err != nil { + return err + } + + functionNames = append(functionNames, methodName) + } + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + methodName := "_" + strings.ToLower(NameSpace) + "_" + strings.ToLower(class.ClassName) + "_" + strings.ToLower(method.MethodName) + + err := writeWasmtimeLambda(w, NameSpace, method, methodName, class.ClassName) + if err != nil { + return err + } + + functionNames = append(functionNames, methodName) + } + } + + for _, functionName := range functionNames { + w.Writeln(" linker.define(\"\", \"%s\", wasmtime::Func::wrap(store, %s)).unwrap();", functionName, functionName) + } + w.Writeln("}") + + w.Writeln(" ") + + w.Writeln("} // namespace %s", NameSpace) + w.Writeln("") + + w.Writeln("#endif // %s", sIncludeGuard) + w.Writeln("") + return nil +} + +func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, ClassIdentifier string) error { + cppClassPrefix := "C" + + baseClass := component.baseClass() + cppBaseClassName := cppClassPrefix + ClassIdentifier + baseClass.ClassName + + sIncludeGuard := "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_IMPLICIT_CPP" - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName - w.Writeln(" friend class %s;", cppClassName) - } + w.Writeln("#ifndef %s", sIncludeGuard) + w.Writeln("#define %s", sIncludeGuard) + w.Writeln("") + w.Writeln("#include \"%s_types.hpp\"", BaseName) w.Writeln("") - w.Writeln("};") + w.Writeln("#include ") + w.Writeln("") - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName + if len(component.ImportedComponentDefinitions) > 0 { + return fmt.Errorf("C++ wasmtime bindings to not support imported components yet") + } - cppParentClassName := "" - inheritanceSpecifier := "" - if !component.isBaseClass(class) { - if class.ParentClass == "" { - cppParentClassName = cppClassPrefix + ClassIdentifier + component.Global.BaseClassName - } else { - cppParentClassName = cppClassPrefix + ClassIdentifier+ class.ParentClass - } - inheritanceSpecifier = fmt.Sprintf(": public %s ", cppParentClassName) - } + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") + w.Writeln("#include ") - w.Writeln(" ") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %s ", cppClassName) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("class %s %s{", cppClassName, inheritanceSpecifier) - w.Writeln("public:") - w.Writeln(" ") - if !component.isBaseClass(class) { - w.Writeln(" /**") - w.Writeln(" * %s::%s - Constructor for %s class.", cppClassName, cppClassName, class.ClassName) - w.Writeln(" */") - w.Writeln(" %s(%s%sWrapper* pWrapper, %sHandle pHandle)", cppClassName, cppClassPrefix, ClassIdentifier, NameSpace) - if cppParentClassName != "" { - w.Writeln(" : %s(pWrapper, pHandle)", cppParentClassName) - } - w.Writeln(" {") - w.Writeln(" }") - w.Writeln(" ") - } else { - err = writeDynamicCppBaseClassMethods(component, baseClass, w, NameSpace, BaseName, cppClassPrefix, ClassIdentifier) - if err != nil { - return err - } + w.Writeln("") + w.Writeln("// imports via WASM linking") + w.Writeln("extern \"C\" {") + for j := 0; j < len(component.Global.Methods); j++ { + method := component.Global.Methods[j] + methodName := "_" + strings.ToLower(NameSpace) + "_" + strings.ToLower(method.MethodName) + + err := writeWasmtimeImport(w, NameSpace, method, methodName, "") + if err != nil { + return err } + } + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err = writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) + methodName := "_" + strings.ToLower(NameSpace) + "_" + strings.ToLower(class.ClassName) + "_" + strings.ToLower(method.MethodName) + + err := writeWasmtimeImport(w, NameSpace, method, methodName, class.ClassName) if err != nil { return err } } - w.Writeln("};") } + w.Writeln("}") + w.Writeln("") - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] + w.Writeln("namespace %s {", NameSpace) + w.Writeln("") + + buildBindingCPPAllForwardDeclarations(component, w, NameSpace, cppClassPrefix, ClassIdentifier) + + writeClassParamDefinition(w, NameSpace) + w.Writeln("") + + writeExceptionClass(w, NameSpace, component.Errors) + w.Writeln("") + + writeCPPInputVector(w, NameSpace, ClassIdentifier) + w.Writeln("") + + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class %s%sWrapper ", cppClassPrefix, ClassIdentifier) + w.Writeln("**************************************************************************************************************************/") + + w.Writeln("class %s%sWrapper {", cppClassPrefix, ClassIdentifier) + w.Writeln("public:") + w.Writeln(" ") + + writeWrapperLifeTimeHandling(w, cppClassPrefix, ClassIdentifier, false) + + w.Writeln(" ") + w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace) + w.Writeln("") + + for _, method := range component.Global.Methods { + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, "Wrapper") + if err != nil { + return err + } + } + w.Writeln("") + w.Writeln(" inline C%s* polymorphicFactory(%sHandle);", component.Global.BaseClassName, NameSpace) + + w.Writeln("") + w.Writeln("private:") + writeCheckBinaryVersion(w, NameSpace, component) + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName + w.Writeln(" friend class %s;", cppClassName) + } + w.Writeln("") + w.Writeln("};") + w.Writeln("") + + err := writeClassDeclarations(w, component, cppClassPrefix, ClassIdentifier, NameSpace, BaseName) + if err != nil { + return err + } - isSpecialFunction, err := CheckHeaderSpecialFunction(method, global); + writePolymorphicFactoryImplementation(w, component, NameSpace, cppClassPrefix, ClassIdentifier, false, true) + w.Writeln("") + + useCPPTypes := true + ExplicitLinking := false + for _, method := range component.Global.Methods { + isSpecialFunction, err := CheckHeaderSpecialFunction(method, component.Global) if err != nil { return err } - + implementationLines := make([]string, 0) - if (isSpecialFunction == eSpecialMethodInjection) { + if isSpecialFunction == eSpecialMethodInjection { implementationLines = append(implementationLines, "bool bNameSpaceFound = false;") sParamName := "s" + method.Params[0].ParamName - for _, subComponent := range(component.ImportedComponentDefinitions) { + for _, subComponent := range component.ImportedComponentDefinitions { theNameSpace := subComponent.NameSpace implementationLines = append(implementationLines, fmt.Sprintf("if (%s == \"%s\") {", sParamName, theNameSpace)) implementationLines = append(implementationLines, fmt.Sprintf(" if (m_p%sWrapper != nullptr) {", theNameSpace)) - implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Library with namespace \" + %s + \" is already registered.\");", NameSpace, strings.ToUpper(NameSpace), sParamName) ) + implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Library with namespace \" + %s + \" is already registered.\");", NameSpace, strings.ToUpper(NameSpace), sParamName)) implementationLines = append(implementationLines, fmt.Sprintf(" }")) implementationLines = append(implementationLines, fmt.Sprintf(" m_p%sWrapper = %s::CWrapper::loadLibraryFromSymbolLookupMethod(p%s);", theNameSpace, theNameSpace, method.Params[1].ParamName)) @@ -1457,76 +2261,18 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s implementationLines = append(implementationLines, fmt.Sprintf("}")) } implementationLines = append(implementationLines, "if (!bNameSpaceFound)") - implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName )) + implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName)) } - err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking) + err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true) if err != nil { return err } - } - w.Writeln(" ") - w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace) - w.Writeln(" {") - w.Writeln(" if (nResult != 0) {") - w.Writeln(" std::string sErrorMessage;") - w.Writeln(" if (pBaseClass != nullptr) {") - w.Writeln(" %s(pBaseClass, sErrorMessage);", component.Global.ErrorMethod) - w.Writeln(" }") - w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace) - w.Writeln(" }") - w.Writeln(" }") - w.Writeln(" ") - w.Writeln("") - - if ExplicitLinking { - w.Writeln(" inline %sResult %s%sWrapper::initWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) - w.Writeln(" {") - - w.AddIndentationLevel(2) - buildDynamicCInitTableCode(component, w, NameSpace, BaseName, false) - w.AddIndentationLevel(-2) - - w.Writeln(" }") - w.Writeln("") - - w.Writeln(" inline %sResult %s%sWrapper::releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) - w.Writeln(" {") - - w.AddIndentationLevel(2) - buildDynamicCReleaseTableCode(component, w, NameSpace, BaseName, "initWrapperTable", false) - w.AddIndentationLevel(-2) - - w.Writeln(" }") - w.Writeln("") - - w.Writeln(" inline %sResult %s%sWrapper::loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) - w.Writeln(" {") - - w.AddIndentationLevel(2) - buildDynamicCLoadTableCode(component, w, NameSpace, BaseName, false) - w.AddIndentationLevel(-2) - - w.Writeln(" }") - - - w.Writeln("") - w.Writeln(" inline %sResult %s%sWrapper::loadWrapperTableFromSymbolLookupMethod(s%sDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) - w.Writeln("{") - - w.AddIndentationLevel(2) - buildDynamicCLoadTableFromSymbolLookupMethodCode(component, w, NameSpace, BaseName, false) - w.AddIndentationLevel(-2) - - w.Writeln("}") - w.Writeln("") - - w.Writeln(" ") - } - + writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace) + w.Writeln("") for i := 0; i < len(component.Classes); i++ { class := component.Classes[i] @@ -1537,13 +2283,12 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln(" */") for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string,0), false, true, false, useCPPTypes, ExplicitLinking) + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true) if err != nil { return err } } } - w.Writeln("") w.Writeln("} // namespace %s", NameSpace) @@ -1555,90 +2300,17 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s return nil } -// BuildBindingCppExplicit builds headeronly C++-bindings of a library's API in form of expliclty loaded function handles. -func BuildBindingCppExplicit(component ComponentDefinition, outputFolder string, outputFolderExample string, - indentString string, ClassIdentifier string) error { - forceRecreation := false - ExplicitLinking := true - namespace := component.NameSpace - libraryname := component.LibraryName - baseName := component.BaseName - - DynamicCHeader := path.Join(outputFolder, baseName+"_dynamic.h") - log.Printf("Creating \"%s\"", DynamicCHeader) - dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) - if err != nil { - return err - } - dynhfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), - true) - err = buildDynamicCCPPHeader(component, dynhfile, namespace, baseName, true, true) - if err != nil { - return err - } - - DynamicCppHeader := path.Join(outputFolder, baseName+"_dynamic.hpp") - log.Printf("Creating \"%s\"", DynamicCppHeader) - dynhppfile, err := CreateLanguageFile(DynamicCppHeader, indentString) - if err != nil { - return err - } - dynhppfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), - true) - err = buildCppHeader(component, dynhppfile, namespace, baseName, ClassIdentifier, ExplicitLinking) - if err != nil { - return err - } - - if len(outputFolderExample) > 0 { - DynamicCPPExample := path.Join(outputFolderExample, namespace+"_example"+".cpp") - if forceRecreation || !FileExists(DynamicCPPExample) { - log.Printf("Creating \"%s\"", DynamicCPPExample) - dyncppexamplefile, err := CreateLanguageFile(DynamicCPPExample, indentString) - if err != nil { - return err - } - dyncppexamplefile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated C++ application that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), - true) - buildDynamicCppExample(component, dyncppexamplefile, outputFolder, ClassIdentifier, ExplicitLinking) - } else { - log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPExample) - } - - DynamicCPPCMake := path.Join(outputFolderExample, "CMakeLists.txt") - if forceRecreation || !FileExists(DynamicCPPCMake) { - log.Printf("Creating \"%s\"", DynamicCPPCMake) - dyncppcmake, err := CreateLanguageFile(DynamicCPPCMake, " ") - if err != nil { - return err - } - dyncppcmake.WriteCMakeLicenseHeader(component, - fmt.Sprintf("This is an autogenerated CMake Project that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), - true) - buildCppDynamicExampleCMake(component, dyncppcmake, outputFolder, outputFolderExample, ExplicitLinking) - } else { - log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPCMake) - } - } - - return nil -} - - -func buildDynamicCppExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string, ClassIdentifier string, ExplicitLinking bool) error { +func buildDynamicCppExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string, ClassIdentifier string, ExplicitLinking bool) { NameSpace := componentdefinition.NameSpace BaseName := componentdefinition.BaseName w.Writeln("#include ") - if (ExplicitLinking) { + if ExplicitLinking { w.Writeln("#include \"%s_dynamic.hpp\"", strings.ToLower(BaseName)) } else { w.Writeln("#include \"%s_implicit.hpp\"", strings.ToLower(BaseName)) } - + w.Writeln("") w.Writeln("") @@ -1646,22 +2318,22 @@ func buildDynamicCppExample(componentdefinition ComponentDefinition, w LanguageW w.Writeln("{") w.Writeln(" try") w.Writeln(" {") - if (ExplicitLinking) { + if ExplicitLinking { w.Writeln(" std::string libpath = (\"\"); // TODO: put the location of the %s-library file here.", NameSpace) - w.Writeln(" auto wrapper = %s::C%sWrapper::loadLibrary(libpath + \"/%s.\"); // TODO: add correct suffix of the library", NameSpace, ClassIdentifier, BaseName,) + w.Writeln(" auto wrapper = %s::C%sWrapper::loadLibrary(libpath + \"/%s.\"); // TODO: add correct suffix of the library", NameSpace, ClassIdentifier, BaseName) } else { w.Writeln(" auto wrapper = %s::C%sWrapper::loadLibrary();", NameSpace, ClassIdentifier) } w.Writeln(" %s_uint32 nMajor, nMinor, nMicro;", NameSpace) w.Writeln(" wrapper->%s(nMajor, nMinor, nMicro);", componentdefinition.Global.VersionMethod) w.Writeln(" std::cout << \"%s.Version = \" << nMajor << \".\" << nMinor << \".\" << nMicro;", NameSpace) - if len(componentdefinition.Global.PrereleaseMethod)>0 { + if len(componentdefinition.Global.PrereleaseMethod) > 0 { w.Writeln(" std::string sPreReleaseInfo;") w.Writeln(" if (wrapper->%s(sPreReleaseInfo)) {", componentdefinition.Global.PrereleaseMethod) w.Writeln(" std::cout << \"-\" << sPreReleaseInfo;") w.Writeln(" }") } - if len(componentdefinition.Global.BuildinfoMethod)>0 { + if len(componentdefinition.Global.BuildinfoMethod) > 0 { w.Writeln(" std::string sBuildInfo;") w.Writeln(" if (wrapper->%s(sBuildInfo)) {", componentdefinition.Global.BuildinfoMethod) w.Writeln(" std::cout << \"+\" << sBuildInfo;") @@ -1696,7 +2368,7 @@ func buildCppDynamicExampleCMake(componentdefinition ComponentDefinition, w Lang } bindingFolder, err := filepath.Rel(outputFolderExample, outputFolder) - if (err != nil) { + if err != nil { return err } bindingFolder = strings.Replace(bindingFolder, "\\", "/", -1) @@ -1706,7 +2378,7 @@ func buildCppDynamicExampleCMake(componentdefinition ComponentDefinition, w Lang w.Writeln("project(%s)", projectName) w.Writeln("set(CMAKE_CXX_STANDARD 11)") w.Writeln("add_executable(%s \"${CMAKE_CURRENT_SOURCE_DIR}/%s_example.cpp\")", projectName, NameSpace) - if (ExplicitLinking || (len(componentdefinition.ImportedComponentDefinitions)>0)) { + if ExplicitLinking || (len(componentdefinition.ImportedComponentDefinitions) > 0) { w.Writeln("if (UNIX)") w.Writeln(" target_link_libraries(%s ${CMAKE_DL_LIBS})", projectName) w.Writeln("endif (UNIX)") @@ -1716,13 +2388,12 @@ func buildCppDynamicExampleCMake(componentdefinition ComponentDefinition, w Lang w.Writeln("target_link_libraries(%s ${%sLOCATION})", projectName, strings.ToUpper(BaseName)) } w.Writeln("target_include_directories(%s PRIVATE \"${%s}\")", projectName, cmakeBindingFolder) - for _, subComponent := range(componentdefinition.ImportedComponentDefinitions) { + for _, subComponent := range componentdefinition.ImportedComponentDefinitions { w.Writeln("target_include_directories(%s PRIVATE \"${%s}/../../../%s_component/Bindings/CppDynamic\")", projectName, cmakeBindingFolder, subComponent.NameSpace) } return nil } - func buildDynamicCExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string, ClassIdentifier string) error { NameSpace := componentdefinition.NameSpace BaseName := componentdefinition.BaseName @@ -1730,7 +2401,7 @@ func buildDynamicCExample(componentdefinition ComponentDefinition, w LanguageWri w.Writeln("#include ") w.Writeln("#include ") w.Writeln("#include \"%s_dynamic.h\"", strings.ToLower(BaseName)) - + w.Writeln("") w.Writeln("") w.Writeln("void releaseWrapper(s%sDynamicWrapperTable* pWrapperTable) {", NameSpace) @@ -1769,12 +2440,12 @@ func buildDynamicCExample(componentdefinition ComponentDefinition, w LanguageWri w.Writeln(" }") w.Writeln(" printf_s(\"%s.Version = %%d.%%d.%%d\", nMajor, nMinor, nMicro);", NameSpace) w.Writeln(" ") - if len(componentdefinition.Global.PrereleaseMethod)>0 || len(componentdefinition.Global.BuildinfoMethod)>0 { + if len(componentdefinition.Global.PrereleaseMethod) > 0 || len(componentdefinition.Global.BuildinfoMethod) > 0 { w.Writeln(" %s_uint32 nBufferRequired = 0;", NameSpace) w.Writeln(" %s_uint8* theString = NULL;", NameSpace) w.Writeln(" bool bHasInfo = false;", NameSpace) } - if len(componentdefinition.Global.PrereleaseMethod)>0 { + if len(componentdefinition.Global.PrereleaseMethod) > 0 { w.Writeln(" eResult = sWrapperTable.m_%s(&bHasInfo, 0, &nBufferRequired, theString);", componentdefinition.Global.PrereleaseMethod) w.Writeln(" if (%s_SUCCESS != eResult) {", strings.ToUpper(NameSpace)) w.Writeln(" releaseWrapper(&sWrapperTable);") @@ -1785,7 +2456,7 @@ func buildDynamicCExample(componentdefinition ComponentDefinition, w LanguageWri w.Writeln(" theString[nBufferRequired] = 0;") w.Writeln(" eResult = sWrapperTable.m_%s(&bHasInfo, nBufferRequired + 1, &nBufferRequired, theString);", componentdefinition.Global.PrereleaseMethod) w.Writeln(" if (%s_SUCCESS != eResult) {", strings.ToUpper(NameSpace)) - w.Writeln(" printf_s(\"Failed to get prerelease information\\n\""); + w.Writeln(" printf_s(\"Failed to get prerelease information\\n\"") w.Writeln(" releaseWrapper(&sWrapperTable);") w.Writeln(" free(theString);") w.Writeln(" return eResult;") @@ -1796,7 +2467,7 @@ func buildDynamicCExample(componentdefinition ComponentDefinition, w LanguageWri w.Writeln(" }") w.Writeln(" ") } - if len(componentdefinition.Global.BuildinfoMethod)>0 { + if len(componentdefinition.Global.BuildinfoMethod) > 0 { w.Writeln(" eResult = sWrapperTable.m_%s(&bHasInfo, 0, &nBufferRequired, theString);", componentdefinition.Global.BuildinfoMethod) w.Writeln(" if (%s_SUCCESS != eResult) {", strings.ToUpper(NameSpace)) w.Writeln(" releaseWrapper(&sWrapperTable);") @@ -1807,7 +2478,7 @@ func buildDynamicCExample(componentdefinition ComponentDefinition, w LanguageWri w.Writeln(" theString[nBufferRequired] = 0;") w.Writeln(" eResult = sWrapperTable.m_%s(&bHasInfo, nBufferRequired + 1, &nBufferRequired, theString);", componentdefinition.Global.BuildinfoMethod) w.Writeln(" if (%s_SUCCESS != eResult) {", strings.ToUpper(NameSpace)) - w.Writeln(" printf_s(\"Failed to get build information\\n\""); + w.Writeln(" printf_s(\"Failed to get build information\\n\"") w.Writeln(" releaseWrapper(&sWrapperTable);") w.Writeln(" free(theString);") w.Writeln(" return eResult;") @@ -1847,7 +2518,7 @@ func buildCDynamicExampleCMake(componentdefinition ComponentDefinition, w Langua } bindingFolder, err := filepath.Rel(outputFolderExample, outputFolder) - if (err != nil) { + if err != nil { return err } bindingFolder = strings.Replace(bindingFolder, "\\", "/", -1) @@ -1858,15 +2529,15 @@ func buildCDynamicExampleCMake(componentdefinition ComponentDefinition, w Langua w.Writeln("project(%s C)", projectName) w.Writeln("") bindingSource := "" - if (ExplicitLinking) { - bindingSource = "\"${"+cmakeBindingFolder+"}/"+strings.ToLower(NameSpace)+"_dynamic.cc\"" + if ExplicitLinking { + bindingSource = "\"${" + cmakeBindingFolder + "}/" + strings.ToLower(NameSpace) + "_dynamic.cc\"" w.Writeln("SET_SOURCE_FILES_PROPERTIES(%s PROPERTIES LANGUAGE C)", bindingSource) bindingSource += "\n" } w.Writeln("add_executable(%s\n \"${CMAKE_CURRENT_SOURCE_DIR}/%s_example.c\"\n %s\n)", projectName, NameSpace, bindingSource) w.Writeln("set_property(TARGET %s PROPERTY C_STANDARD 99)", projectName) - if (ExplicitLinking) { + if ExplicitLinking { w.Writeln("if (UNIX)") w.Writeln(" target_link_libraries(%s ${CMAKE_DL_LIBS})", projectName) w.Writeln("endif (UNIX)") diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 030fba7e..d8b956e4 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -62,12 +62,16 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo dynhfile.WriteCLicenseHeader(component, fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", component.LibraryName), true) - err = buildDynamicCCPPHeader(component, dynhfile, component.NameSpace, component.BaseName, false, false) + err = buildDynamicCCPPHeader(component, dynhfile, component.NameSpace, component.BaseName, false, false, false) + if err != nil { + return err + } + err = writeGoCDeclarations(component, dynhfile) if err != nil { return err } - DynamicCImpl := path.Join(outputFolder, component.BaseName+"_dynamic.cc") + DynamicCImpl := path.Join(outputFolder, component.BaseName+"_dynamic.c") log.Printf("Creating \"%s\"", DynamicCImpl) dyncppfile, err := CreateLanguageFile(DynamicCImpl, indentString) if err != nil { @@ -82,6 +86,11 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo return err } + err = writeGoCDefinitions(component, dyncppfile) + if err != nil { + return err + } + fnFile, err := CreateLanguageFile(path.Join(outputFolder, "cfunc.go"), " ") if err != nil { return err @@ -453,7 +462,7 @@ func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, } // WriteCGoAbiMethod writes an ABI method in CGo-Style -func WriteCGoAbiMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool) error { +func WriteCGoAbiMethodDeclaration(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool) error { CMethodName := "" var parameters, callParameters []string if isGlobal { @@ -471,7 +480,38 @@ 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("") + + return nil +} + +func WriteCGoAbiMethodDefinition(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool) error { + CMethodName := "" + var parameters, callParameters []string + if isGlobal { + CMethodName = fmt.Sprintf("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) + } else { + CMethodName = fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName)) + parameters = append(parameters, fmt.Sprintf("%s_%s p%s", NameSpace, ClassName, ClassName)) + callParameters = append(callParameters, fmt.Sprintf("p%s", ClassName)) + } + + for k := 0; k < len(method.Params); k++ { + param := method.Params[k] + cParams, err := generateCCPPParameter(param, ClassName, method.MethodName, NameSpace, false) + if err != nil { + return err + } + for _, cParam := range cParams { + parameters = append(parameters, cParam.ParamType+" "+cParam.ParamName) callParameters = append(callParameters, cParam.ParamName) } @@ -496,45 +536,51 @@ func WriteCGoAbiMethod(method ComponentDefinitionMethod, w LanguageWriter, NameS return nil } -func writeGoCCall(component ComponentDefinition, method ComponentDefinitionMethod, w LanguageWriter, className string, isGlobal bool) error { - err := WriteCGoAbiMethod(method, w, component.NameSpace, className, isGlobal) +func writeGoCDefinition(component ComponentDefinition, method ComponentDefinitionMethod, w LanguageWriter, className string, isGlobal bool) error { + err := WriteCGoAbiMethodDefinition(method, w, component.NameSpace, className, isGlobal) if err != nil { return err } return nil } -func writeGoCCalls(component ComponentDefinition, w LanguageWriter) error { +func writeGoCDeclaration(component ComponentDefinition, method ComponentDefinitionMethod, w LanguageWriter, className string, isGlobal bool) error { + err := WriteCGoAbiMethodDeclaration(method, w, component.NameSpace, className, isGlobal) + if err != nil { + return err + } + return nil +} + +func writeGoCDeclarations(component ComponentDefinition, w LanguageWriter) error { + + w.Writeln("%sHandle load%sLibrary (const char * pFileName);", component.NameSpace, component.NameSpace) + w.Writeln("") + w.Writeln("void unload%sLibrary (%sHandle nLibraryHandle);", component.NameSpace, component.NameSpace) + w.Writeln("") + for _, class := range component.Classes { for _, method := range class.Methods { - err := writeGoCCall(component, method, w, class.ClassName, false) + err := writeGoCDeclaration(component, method, w, class.ClassName, false) if err != nil { return err } } } for _, method := range component.Global.Methods { - err := writeGoCCall(component, method, w, "Wrapper", true) + err := writeGoCDeclaration(component, method, w, "Wrapper", true) if err != nil { return err } } + sIncludeGuard := "__" + strings.ToUpper(component.NameSpace) + "_DYNAMICHEADER" + w.Writeln("#endif // %s", sIncludeGuard) return nil } -func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { - - var err error - - packageName := strings.ToLower(component.BaseName) +func writeGoCDefinitions(component ComponentDefinition, w LanguageWriter) error { - w.Writeln("") - 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) @@ -566,6 +612,38 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("}") w.Writeln("") + for _, class := range component.Classes { + for _, method := range class.Methods { + err := writeGoCDefinition(component, method, w, class.ClassName, false) + if err != nil { + return err + } + } + } + for _, method := range component.Global.Methods { + err := writeGoCDefinition(component, method, w, "Wrapper", true) + if err != nil { + return err + } + } + return nil + +} + +func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { + + var err error + + packageName := strings.ToLower(component.BaseName) + + w.Writeln("") + w.Writeln("package %s", packageName) + w.Writeln("") + w.Writeln("/*") + w.Writeln("#cgo linux LDFLAGS: -ldl") + w.Writeln("#include \"%s_dynamic.h\"", packageName) + w.Writeln("") + /* TODO! err = buildCFuncsForward(component, w) @@ -573,12 +651,6 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { return err } */ - - err = writeGoCCalls(component, w) - if err != nil { - return err - } - w.Writeln("*/") w.Writeln("import \"C\"") w.Writeln("") @@ -756,7 +828,11 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( case "class": tp.Type = paramClass tp.CType = fmt.Sprintf("C.%s_%s", namespace, paramClass) - tp.CToGo = "" + if isPtr { + tp.CToGo = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", tp.Type, paramName) + } else { + tp.CToGo = fmt.Sprintf("*(*%s)(unsafe.Pointer(&%s))", tp.Type, paramName) + } tp.GoToC = fmt.Sprintf("%s.Ref", paramName) tp.Empty = paramClass + "{}" case "optionalclass": @@ -769,7 +845,7 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( tp.Type = paramClass + "Func" tp.CType = fmt.Sprintf("C.%s%s", namespace, paramClass) tp.CToGo = "" - tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(C.%s%s_cgo))", tp.CType, namespace, paramClass) + tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&%s))", tp.CType, paramName) tp.Empty = "0" case "structarray": tp.Type = fmt.Sprintf("[]%s", paramClass) @@ -784,7 +860,7 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( } tp.Type = ptrStr + fmt.Sprintf("[]%s", btp.Type) tp.CType = fmt.Sprintf("*%s", btp.CType) - tp.CToGo = fmt.Sprintf("([]%s)(unsafe.Pointer(&%s[0]))", tp.Type, paramName) + tp.CToGo = fmt.Sprintf("*(*%s)(unsafe.Pointer(%s))", tp.Type, paramName) tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&%s[0]))", tp.CType, paramName) tp.Empty = "nil" default: