{"id":17128299,"url":"https://github.com/elinorbgr/dlib","last_synced_at":"2025-04-09T14:07:32.010Z","repository":{"id":36290776,"uuid":"40595304","full_name":"elinorbgr/dlib","owner":"elinorbgr","description":"A dynamic library helper for rust crates","archived":false,"fork":false,"pushed_at":"2023-06-05T08:56:47.000Z","size":38,"stargazers_count":35,"open_issues_count":4,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-02T12:07:05.253Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elinorbgr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-12T10:37:56.000Z","updated_at":"2025-03-05T00:53:54.000Z","dependencies_parsed_at":"2024-06-19T05:27:41.701Z","dependency_job_id":null,"html_url":"https://github.com/elinorbgr/dlib","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elinorbgr%2Fdlib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elinorbgr%2Fdlib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elinorbgr%2Fdlib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elinorbgr%2Fdlib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elinorbgr","download_url":"https://codeload.github.com/elinorbgr/dlib/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248054208,"owners_count":21039952,"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":[],"created_at":"2024-10-14T19:06:43.154Z","updated_at":"2025-04-09T14:07:31.952Z","avatar_url":"https://github.com/elinorbgr.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![crates.io](https://img.shields.io/crates/v/dlib.svg)](https://crates.io/crates/dlib)\n[![docs.rs](https://docs.rs/dlib/badge.svg)](https://docs.rs/dlib)\n\n# dlib\n\ndlib is a small crate providing macros to make easy the use of external system libraries that\ncan or cannot be optionally loaded at runtime, depending on whether a certain feature is enabled.\n\n### Usage\n\ndlib defines the `external_library!` macro, which can be invoked in this way:\n\n```rust\nexternal_library!(feature=\"dlopen-foo\", Foo, \"foo\",\n    statics:\n        me: c_int,\n        you: c_float,\n    functions:\n        fn foo() -\u003e c_int,\n        fn bar(c_int, c_float) -\u003e (),\n        fn baz(*const c_int) -\u003e c_int,\n    varargs:\n        fn blah(c_int, c_int ...) -\u003e *const c_void,\n        fn bleh(c_int ...) -\u003e (),\n);\n```\n\nAs you can see, it is required to separate static values from functions and from function\nhaving variadic arguments. Each of these 3 categories is optional, but the ones used must appear\nin this order. Return types of the functions must all be explicit (hence `-\u003e ()` for void functions).\n\nIf the feature named by the `feature` argument (in this example, `dlopen-foo`) is absent on your crate,\nthis macro will expand to an extern block defining each of the items, using the third argument\nof the macro as a link name:\n\n```rust\n#[link(name = \"foo\")]\nextern \"C\" {\n    pub static me: c_int;\n    pub static you: c_float;\n    pub fn foo() -\u003e c_int;\n    pub fn bar(_: c_int, _: c_float) -\u003e ();\n    pub fn baz(_: *const c_int) -\u003e c_int;\n    pub fn blah(_: c_int, _: c_int, ...) -\u003e *const c_void;\n    pub fn bleh(_: c_int, ...) -\u003e ();\n}\n\n```\n\nIf the feature named by the `feature` argument is present on your crate, it will expand to a\n`struct` named by the second argument of the macro, with one field for each of the symbols defined;\nand a method `open`, which tries to load the library from the name or path given as an argument.\n\n```rust\npub struct Foo {\n    pub me: \u0026'static c_int,\n    pub you: \u0026'static c_float,\n    pub foo: unsafe extern \"C\" fn() -\u003e c_int,\n    pub bar: unsafe extern \"C\" fn(c_int, c_float) -\u003e (),\n    pub baz: unsafe extern \"C\" fn(*const c_int) -\u003e c_int,\n    pub blah: unsafe extern \"C\" fn(c_int, c_int, ...) -\u003e *const c_void,\n    pub bleh: unsafe extern \"C\" fn(c_int, ...) -\u003e (),\n}\n\n\nimpl Foo {\n    pub unsafe fn open(name: \u0026str) -\u003e Result\u003cFoo, DlError\u003e { /* ... */ }\n}\n```\n\nThis method returns `Ok(..)` if the loading was successful. It contains an instance of the defined struct\nwith all of its fields pointing to the appropriate symbol.\n\nIf the library specified by `name` could not be openened, it returns `Err(DlError::CantOpen(e))`, with\n`e` the error reported by `libloading` (see [LibLoadingError]);\n\nIt will also fail on the first missing symbol, with `Err(DlError::MissingSymbol(symb))` where `symb`\nis a `\u0026str` containing the missing symbol name.\n\nNote that this method is unsafe, as loading (and unloading on drop) an external C library can run arbitrary\ncode. As such, you need to ensure that the specific library you want to load is safe to load in the context\nyou want to load it.\n\n### Remaining generic in your crate\n\nIf you want your crate to remain generic over dlopen vs. linking, simply add a feature to your `Cargo.toml`:\n\n```toml\n[dependencies]\ndlib = \"0.5\"\n\n[features]\ndlopen-foo = []\n```\n\nThen give the name of that feature as the `feature` argument to dlib's macros:\n\n```rust\nexternal_library!(feature=\"dlopen-foo\", Foo, \"foo\",\n    functions:\n        fn foo() -\u003e c_int,\n);\n```\n\n`dlib` provides helper macros to dispatch the access to foreign symbols:\n\n```rust\nffi_dispatch!(feature=\"dlopen-foo\", Foo, function, arg1, arg2);\nffi_dispatch_static!(feature=\"dlopen-foo\", Foo, my_static_var);\n```\n\nThese will expand to the appropriate value or function call depending on the presence or absence of the\n`dlopen-foo` feature on your crate.\n\nYou must still ensure that the functions/statics or the wrapper struct `Foo` are in scope. For example,\nyou could use the [`lazy_static`](https://crates.io/crates/lazy_static) crate to do the initialization,\nand store the wrapper struct in a static variable that you import wherever needed:\n\n```rust\n#[cfg(feature = \"dlopen-foo\")]\nlazy_static::lazy_static! {\n    pub static ref FOO_STATIC: Foo =\n        Foo::open(\"libfoo.so\").ok().expect(\"could not find libfoo\");\n}\n```\n\nThen, it can become as simple as putting this on top of all modules using the FFI:\n\n```rust\n#[cfg(feature = \"dlopen-foo\")]\nuse ffi::FOO_STATIC;\n#[cfg(not(feature = \"dlopen-foo\"))]\nuse ffi::*;\n```\n\nLicense: MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felinorbgr%2Fdlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felinorbgr%2Fdlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felinorbgr%2Fdlib/lists"}