mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-01 12:18:15 +00:00
sync with main
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Odin binding generator from C header data.
|
||||
*/
|
||||
|
||||
package bindgen
|
||||
|
||||
import "core:os"
|
||||
import "core:fmt"
|
||||
import "core:runtime"
|
||||
|
||||
GeneratorOptions :: struct {
|
||||
mode : string, // "odin" or "jai"
|
||||
|
||||
// Variable
|
||||
variableCase : Case,
|
||||
|
||||
// Defines
|
||||
definePrefixes : []string,
|
||||
defineTransparentPrefixes : []string,
|
||||
definePostfixes : []string,
|
||||
defineTransparentPostfixes : []string,
|
||||
defineCase : Case,
|
||||
|
||||
// Pseudo-types
|
||||
pseudoTypePrefixes : []string,
|
||||
pseudoTypeTransparentPrefixes : []string,
|
||||
pseudoTypePostfixes : []string,
|
||||
pseudoTypeTransparentPostfixes : []string,
|
||||
pseudoTypeCase : Case,
|
||||
|
||||
// Enums
|
||||
enumConsideredFlagsPostfixes : []string,
|
||||
|
||||
// Functions
|
||||
functionPrefixes : []string,
|
||||
functionTransparentPrefixes : []string,
|
||||
functionPostfixes : []string,
|
||||
functionTransparentPostfixes : []string,
|
||||
functionCase : Case,
|
||||
|
||||
// Enum values
|
||||
enumValuePrefixes : []string,
|
||||
enumValueTransparentPrefixes : []string,
|
||||
enumValuePostfixes : []string,
|
||||
enumValueTransparentPostfixes : []string,
|
||||
enumValueCase : Case,
|
||||
enumValueNameRemove : bool,
|
||||
enumValueNameRemovePostfixes : []string,
|
||||
|
||||
parserOptions : ParserOptions,
|
||||
}
|
||||
|
||||
GeneratorData :: struct {
|
||||
handle : os.Handle,
|
||||
nodes : Nodes,
|
||||
|
||||
// References
|
||||
foreignLibrary : string,
|
||||
options : ^GeneratorOptions,
|
||||
}
|
||||
|
||||
generate :: proc(
|
||||
packageName : string,
|
||||
foreignLibrary : string,
|
||||
outputFile : string,
|
||||
headerFiles : []string,
|
||||
options : GeneratorOptions,
|
||||
) {
|
||||
options := options;
|
||||
data : GeneratorData;
|
||||
data.options = &options;
|
||||
data.foreignLibrary = foreignLibrary;
|
||||
|
||||
if options.mode == "" {
|
||||
options.mode = "odin";
|
||||
}
|
||||
|
||||
// Outputing odin file
|
||||
errno : os.Errno;
|
||||
|
||||
// chmod 664 when creating file
|
||||
mode: int = 0;
|
||||
when os.OS == "linux" || os.OS == "darwin" {
|
||||
mode = os.S_IRUSR | os.S_IWUSR | os.S_IRGRP | os.S_IWGRP | os.S_IROTH;
|
||||
}
|
||||
|
||||
data.handle, errno = os.open(outputFile, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, mode);
|
||||
if errno != 0 {
|
||||
fmt.eprint("[bindgen] Unable to write to output file ", outputFile, " (", errno ,")\n");
|
||||
return;
|
||||
}
|
||||
defer os.close(data.handle);
|
||||
|
||||
if options.mode == "jai" {
|
||||
fcat(data.handle, foreignLibrary, " :: #foreign_library \"", foreignLibrary, "\";\n");
|
||||
fcat(data.handle, "\n");
|
||||
} else {
|
||||
fcat(data.handle, "package ", packageName, "\n");
|
||||
fcat(data.handle, "\n");
|
||||
fcat(data.handle, "foreign import \"", foreignLibrary, "\"\n");
|
||||
fcat(data.handle, "\n");
|
||||
fcat(data.handle, "import _c \"core:c\"\n");
|
||||
fcat(data.handle, "\n");
|
||||
}
|
||||
|
||||
// Parsing header files
|
||||
anonymousStructCount = 0;
|
||||
anonymousUnionCount = 0;
|
||||
anonymousEnumCount = 0;
|
||||
|
||||
for headerFile in headerFiles {
|
||||
bytes, ok := os.read_entire_file(headerFile);
|
||||
if !ok {
|
||||
fmt.eprint("[bindgen] Unable to read file ", headerFile, "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// We fuse the SOAs
|
||||
headerNodes := parse(bytes, options.parserOptions);
|
||||
merge_generic_nodes(&data.nodes.defines, &headerNodes.defines);
|
||||
merge_generic_nodes(&data.nodes.enumDefinitions, &headerNodes.enumDefinitions);
|
||||
merge_generic_nodes(&data.nodes.unionDefinitions, &headerNodes.unionDefinitions);
|
||||
merge_forward_declared_nodes(&data.nodes.structDefinitions, &headerNodes.structDefinitions);
|
||||
merge_generic_nodes(&data.nodes.functionDeclarations, &headerNodes.functionDeclarations);
|
||||
merge_generic_nodes(&data.nodes.typedefs, &headerNodes.typedefs);
|
||||
}
|
||||
|
||||
// Exporting
|
||||
export_defines(&data);
|
||||
export_typedefs(&data);
|
||||
export_enums(&data);
|
||||
export_structs(&data);
|
||||
export_unions(&data);
|
||||
|
||||
// Foreign block for functions
|
||||
if options.mode != "jai" {
|
||||
foreignLibrarySimple := simplify_library_name(foreignLibrary);
|
||||
fcat(data.handle, "@(default_calling_convention=\"c\")\n");
|
||||
fcat(data.handle, "foreign ", foreignLibrarySimple, " {\n");
|
||||
fcat(data.handle, "\n");
|
||||
}
|
||||
|
||||
export_functions(&data);
|
||||
|
||||
if options.mode != "jai" {
|
||||
fcat(data.handle, "}\n");
|
||||
}
|
||||
}
|
||||
|
||||
// system:foo.lib -> foo
|
||||
simplify_library_name :: proc(libraryName : string) -> string {
|
||||
startOffset := 0;
|
||||
endOffset := len(libraryName);
|
||||
|
||||
for c, i in libraryName {
|
||||
if startOffset == 0 && c == ':' {
|
||||
startOffset = i + 1;
|
||||
}
|
||||
else if c == '.' {
|
||||
endOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return libraryName[startOffset:endOffset];
|
||||
}
|
||||
|
||||
merge_generic_nodes :: proc(nodes : ^$T, headerNodes : ^T) {
|
||||
for headerNode in headerNodes {
|
||||
// Check that there are no duplicated nodes (due to forward declaration or such)
|
||||
duplicatedIndex := -1;
|
||||
for i := 0; i < len(nodes); i += 1 {
|
||||
node := nodes[i];
|
||||
if node.name == headerNode.name {
|
||||
duplicatedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if duplicatedIndex < 0 {
|
||||
append(nodes, headerNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
merge_forward_declared_nodes :: proc(nodes : ^$T, headerNodes : ^T) {
|
||||
for headerNode in headerNodes {
|
||||
// Check that there are no duplicated nodes (due to forward declaration or such)
|
||||
duplicatedIndex := -1;
|
||||
for i := 0; i < len(nodes); i += 1 {
|
||||
node := nodes[i];
|
||||
if node.name == headerNode.name {
|
||||
duplicatedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if duplicatedIndex < 0 {
|
||||
append(nodes, headerNode);
|
||||
}
|
||||
else if !headerNode.forwardDeclared && len(headerNode.members) > 0 {
|
||||
nodes[duplicatedIndex] = headerNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user