{"id":21339082,"url":"https://github.com/capsadmin/ffibuild","last_synced_at":"2025-07-12T14:31:38.388Z","repository":{"id":41811340,"uuid":"50772590","full_name":"CapsAdmin/ffibuild","owner":"CapsAdmin","description":"generates luajit ffi bindings from c headers","archived":false,"fork":false,"pushed_at":"2018-03-24T12:43:52.000Z","size":1707,"stargazers_count":58,"open_issues_count":0,"forks_count":4,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-05-02T01:06:41.445Z","etag":null,"topics":["binding-generator","cparser","ffi","luajit"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CapsAdmin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-31T12:08:30.000Z","updated_at":"2024-04-27T14:26:41.000Z","dependencies_parsed_at":"2022-09-07T10:13:02.067Z","dependency_job_id":null,"html_url":"https://github.com/CapsAdmin/ffibuild","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CapsAdmin%2Fffibuild","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CapsAdmin%2Fffibuild/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CapsAdmin%2Fffibuild/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CapsAdmin%2Fffibuild/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CapsAdmin","download_url":"https://codeload.github.com/CapsAdmin/ffibuild/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225825236,"owners_count":17529905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binding-generator","cparser","ffi","luajit"],"created_at":"2024-11-22T00:42:19.097Z","updated_at":"2024-11-22T00:42:19.670Z","avatar_url":"https://github.com/CapsAdmin.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"ffibuild is a utility to generate FFI bindings for LuaJIT. It can use the Nix package manager to automatically setup the build environment and build the library you want. \n\nThere are also helper functions to build more manually, but this assumes you have the  required packages to build.\n\nffibuild is used on Linux and macOS. Because it assumes a posix ish environment it does not work on Windows. Nix reportedly works on Windows under Cygwin but I'm not sure how to get it working properly.\n\nMost of the examples use Nix, some build manually and some do not really use the ffibuild system but are there for completeness and use in [goluwa](https://gitlab.com/CapsAdmin/goluwa).\n\n\n## simple example:\n\n```lua\nlocal code = \"local CLIB = ffi.load('purple')\\n\"\ncode = code .. \"local library = {}\\n\"\n\nlocal header = ffibuild.ProcessSourceFileGCC([[\n\t#define PURPLE_PLUGINS\n\t#include \u003clibpurple/purple.h\u003e\n]], \"$(pkg-config purple --cflags)\")\n\nlocal meta_data = ffibuild.GetMetaData(header)\n\nfor func_name, func_type in pairs(meta_data.functions) do\n\tlocal friendly_name = ffibuild.ChangeCase(func_name, \"foo_bar\", \"fooBar\")\n\tcode = code .. \"library.\" .. friendly_name .. \" = \" .. ffibuild.BuildLuaFunction(func_name, func_type) .. \"\\n\"\nend\n\ncode = code .. \"return library\\n\"\n```\n\nThis creates a bunch of globals from this_casing to thisCasing based header input.\n\n\n\n## ffi.GetMetaData(header)\nffi.GetMetaData returns a table structured like so\n\n```lua\n{\n\tfunctions = {[function], ...},\n\tstructs = {struct _PurpleAccount = [struct], struct _PurpleBuddy = [struct]},\n\tunions = {union _PurpleAccount = [union], ...},\n\ttypedefs = {gboolean = [type], gint = [type], ...},\n\tvariables = {[variable], ...},\n\tenums = {[enums], [enums], [enums]},\n\tglobal_enums = {[enums], [enums], [enums]},\n} = ffibuild.GetMetaData(header)\n```\n\nWhere [???] represents a type object.\n\nthe returned meta_data also has some functions.\n\n```lua\nmeta_data:GetStructTypes(pattern) -- returns a table with all structs whose tag matches the pattern\nmeta_data:FindFunctions(pattern, from, to) -- returns a table with all functions whose name matches the pattern. from and to is just a shortcut for ffibuild.ChangeCase(str, from, to)\nmeta_data:GetFunctionsStartingWithType(type) -- returns a table with all functions that starts with the type (useful for object functions)\nmeta_data:BuildMinimalHeader(check_function, check_enum, keep_structs) -- returns a minimal header where check function and enum are used as filters and keep_structs make it so structs are not empty (which might not be useful)\nmeta_data:BuildFunctions(pattern) -- this builds a table of functions and somewhat automates the first example in this readme\nmeta_data:BuildEnums(pattern) -- this builds a table of enums. usually in examples enums are built so they can be accessed like library.e.FOO\n```\n\n\n## types\n```lua\n-- all functions that take meta_data will attempt to get the most primitive type or declaration\nstring = type:GetDeclaration(meta_data) -- Gets the declaration for the type such as \"const char *\", \"void (*)(int, char)\", \"enums {FOO=1,BAR=2}\", etc\nstring = type:GetBasicType(meta_data) -- Gets the basic type such as if type:GetDeclaration() would return \"const char *\" type:GetbasicType() would return \"char\"\n[type] = type:GetPrimitive(meta_data) -- Attempts to get the primitive type.\n```\n\n## functions\n```lua\nfunc_type:GetDeclaration(as_callback) -- gets the function declaration or as a callback if requested. A function cold also be a callback intitially and so GetDeclaration would return that by default.\n\nif func_type.arguments then\n\tfor arg_pos, type in ipairs(func_type.arguments) do\n\t\t-- see type section above\n\t\ttype.name -- the name of this argument if any\n\tend\nend\n\nfunc_type.return_type -- the return argument type\n```\n\n## trimming the header and evaluating types\n\nIn the first example you would get glib functions exported as well since purple uses them internally. This is generally not wanted but you can use `meta_data:BuildMinimalHeader(check_function, check_enum, keep_structs)` where check_function would be a function to find c functions. Based on the functions you need it will return a stripped down header based on the function arguments.\n\n```lua\n    local header = meta_data:BuildMinimalHeader(function(name) return name:find(\"^purple_\") end, function(name) return name:find(\"PURPLE_\") end, true)\n```\n\nThis would return a header with all functions that start with `purple_` and the required structs, unions and enums based on what those functions need. The check enum function will just remove any global or typedef enum that don't start with `PURPLE_`\n\n## caveats:\n\nSometimes you need to hack the meta data so ffi.cdef can understand it. For instance:\n\n* #define enums can sometimes be problematic, however there are tools to deal with this\n* sometimes a library can define a function that uses problematic types.\n\nThe examples provided should explain some of these workarounds to get an idea of what you need to do. Usually the easy way is to make the problematic type `void *`\n\n## todo\n* Get this and Nix working in msys2 somehow. \u003chttps://gist.github.com/CapsAdmin/ee77100c499ec9a55730e999759a166b\u003e\n* Provide nix expressions for lesser known libraries (VTFLib, graphene, etc)\n* Don't strip out pragma pack and other compiler specific things\n* Make struct to table functions\n* Have a way to make anonymous definitions using typeof and parameterized types\n* add a way to prefix types for \"namespaces\" to avoid conflicting libraries\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapsadmin%2Fffibuild","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcapsadmin%2Fffibuild","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapsadmin%2Fffibuild/lists"}