Files
llgo/doc/cpp-auto-tool-architecture-documentation.md
morpingsss 635eea7acb docs(llgo/doc) add cpp-auto-tool-architecture-documentation (#547)
* docs(llgo/doc) add cpp-auto-tool-architecture-documentation
2024-07-23 08:27:01 +08:00

5.6 KiB

C++ Automation Tool Architecture Documentation

Overall Approach

Modules

  1. Parsing Module
  2. Function Declaration Generation Module
  3. Code Generation Module

Process

  1. The Parsing Module reads config.json to obtain dynamic libraries, header files, and the package name. After parsing, it writes the generated common_symbol_info.json path into config.json.
  2. The Function Declaration Generation Module reads config.json to get the package name, header files, and the previously generated common_symbol_info.json. After parsing, it generates the function prototype func_prototype.json.
  3. Reads the previously generated func_prototype.json, stores it as a structure, and uses gogen to generate code based on the structure.

Parsing Module

Input

Obtains the paths to header files and dynamic library files by reading the JSON file config.json.

{
  "PackageName": "inireader",
  "HeaderFiles": [
    "/path/to/header/INIReader.h",
    "/path/to/header/AnotherHeader.h"
  ],
  "DLLFile": "/path/to/lib/libINIReader.dylib",
  "JSONFile": "/path/to/json/config.json"
}
./generate_symbol_table /path/to/config.json

Implementation Steps

  1. Parse dylib and store:
// common.go
type CPPSymbol struct {
    Address string
    Type    string
    Name    string
}

// parser_dylib.go
func ParseDylibSymbols(dylibPath string) ([]common.CPPSymbol, error)
  1. Parse header files and store:
// common.go
type ASTInformation struct {
    Namespace   string
    Class       string
    Name        string
    BaseClasses []string
    ReturnType  string
    Location    string
    Parameters  []Parameter
    Symbol      string
}

type Parameter struct {
    Name string
    Type string
}

// parser_ast.go
func ParseHeaderFile(files []string) ([]common.ASTInformation, error)
  1. Cross-reference data from the first two steps to get the final output
// common.go
type CommonSymbolInfo struct {
    FunctionName       string
    Symbol             string
    Location           string
    UserFunctionName   string
}

// common_symbols.go
func GetCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTInformation) []common.CommonSymbolInfo
  1. Generate common_symbol_info.json file and store the JSON file path into config.json
// generator.go
func GenerateJSON([]CommonSymbolInfo)
  1. Example common_symbol_info.json file
{
    "FunctionName": "A::B::C",
    "Symbol": "_ZN9INIReaderC1ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE",
    "Location": "a.h",
    "UserFunctionName": "CFromA"
}

Function Declaration Generation Module

Input

No input required, directly reads the config.json file

Implementation Steps

  1. Execute the executable
./generate_func_decl /path/to/config.json
  1. Parse header files
// common.go
type ASTInformation struct {
    Namespace   string
    Class       string
    Name        string
    BaseClasses []string
    ReturnType  string
    Location    string
    Parameters  []Parameter
}

type Parameter struct {
    Name string
    Type string
}

// parser_ast.go
func ParseHeaderFile(filePath string) ([]common.ASTInformation, error)
  1. Generate the final JSON mapping file func_prototype.json
 func GenerateJSONFile(info []common.ASTInformation)
{
    "FunctionName": "A::B::C",
    "Symbol": "_ZN9INIReaderC1ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE",
    "Location": "a.h",
    "ReturnType" : "int",
    "UserFunctionName": "CFromA",
    "Parameters" : [
        {
            "arg1" : "int"
        },
        {
            "arg2" : "*char"
        }
    ]
}

Code Generation Module

Input

No input required, directly reads func_prototype.json file

Implementation Steps

  1. Execute the executable
./generate_code /path/to/func_prototype.json
  1. Parse JSON file
// common.go
type HeaderFileInfo struct {
    FunctionName     string
    Symbol           string
    Location         string
    UserFunctionName string
    Parameters       map[string]string
}

// parse_json.go
func ParseJSON(jsonFilePath string) ([]common.HeaderFileInfo, error)
  1. Generate code using the parsed structure with gogen
// generator.go
func GenerateCode(info []common.HeaderFileInfo) {
    pkg := gogen.NewPackage("", PackageName, nil)
    cm := comment(fmt.Sprintf("llgo:link %s %s", funcName1, symbol1))
    pkg.NewFunc(recv, funcName, params, results, variadic).SetComments(pkg, cm).BodyStart(pkg).End()
}

Output

  1. Directory structure
package_name/
├── _demo
    ├── demo1.go
└── llgo_link.go
└── a.go
└── b.go
└── c.go

Note that demo1.go file needs to be written by the user

  1. llgo_link.go is responsible for linking configuration
package inih
const (
        LLGoFiles   = "$(pkg-config --cflags INIReader): _wrap/reader.cpp"
        LLGoPackage = "link: $(pkg-config --libs inih INIReader); -linih -lINIReader"
)
  1. Example content for a.go
package inih
import (
        _ "unsafe"
        "github.com/goplus/llgo/c"
)
//go:linkname Parse C.ini_parse
func Parse(filename *c.Char, handler func(user c.Pointer, section *c.Char, name *c.Char, value *c.Char) c.Int, user c.Pointer) c.Int

//go:linkname ParseFile C.ini_parse_file
func ParseFile(file c.FilePtr, handler func(user c.Pointer, section *c.Char, name *c.Char, value *c.Char) c.Int, user c.Pointer) c.Int

//go:linkname ParseString C.ini_parse_string
func ParseString(str *c.Char, handler func(user c.Pointer, section *c.Char, name *c.Char, value *c.Char) c.Int, user c.Pointer) c.Int