{"id":26600799,"url":"https://github.com/n0bra1n3r/cinterop","last_synced_at":"2025-09-07T12:35:57.258Z","repository":{"id":41807935,"uuid":"409166726","full_name":"n0bra1n3r/cinterop","owner":"n0bra1n3r","description":"A C/C++ interop library for the Nim programming language","archived":false,"fork":false,"pushed_at":"2023-02-24T23:41:02.000Z","size":67,"stargazers_count":77,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"staging","last_synced_at":"2025-07-09T07:04:52.492Z","etag":null,"topics":["c","cplusplus","cpp","interop","nim","nim-lang"],"latest_commit_sha":null,"homepage":"","language":"Nim","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/n0bra1n3r.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-22T10:53:17.000Z","updated_at":"2025-06-30T12:57:24.000Z","dependencies_parsed_at":"2025-03-23T18:47:47.806Z","dependency_job_id":null,"html_url":"https://github.com/n0bra1n3r/cinterop","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/n0bra1n3r/cinterop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n0bra1n3r%2Fcinterop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n0bra1n3r%2Fcinterop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n0bra1n3r%2Fcinterop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n0bra1n3r%2Fcinterop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/n0bra1n3r","download_url":"https://codeload.github.com/n0bra1n3r/cinterop/tar.gz/refs/heads/staging","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n0bra1n3r%2Fcinterop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274039211,"owners_count":25211901,"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","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["c","cplusplus","cpp","interop","nim","nim-lang"],"created_at":"2025-03-23T18:35:25.547Z","updated_at":"2025-09-07T12:35:57.228Z","avatar_url":"https://github.com/n0bra1n3r.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cinterop\n\n![Testing](https://github.com/n0bra1n3r/cinterop/actions/workflows/test.yml/badge.svg)\n\nA C/C++ interop library for the [Nim](https://nim-lang.org/) programming\nlanguage.\n\nThis project was directly inspired by the [nimline](https://github.com/sinkingsugar/nimline)\nlibrary.\n\n## Overview\n\nSimilar to nimline, this library allows one to interop with C/C++ code without\nhaving to create wrappers. Unlike nimline, cinterop does not depend on Nim's\nexperimental [dotOperators](https://nim-lang.org/docs/manual_experimental.html#special-operators)\nfeature and relies only on Nim's macro system to generate code.\n\nFeatures include:\n\n* No dependencies other than Nim's standard library.\n* Convenience macros to declare C/C++ types and functions ([decls.nim](src/cinterop/decls.nim)).\n* Conversion of a subset of Nim to its syntactical equivalent in C/C++ without\nrequiring forward declarations ([exprs.nim](src/cinterop/exprs.nim)).\n\nThis project **is not** a replacement for hand-written wrappers or wrapper\ngenerators like [c2nim](https://github.com/nim-lang/c2nim). This library is\nuseful for **quickly prototyping** new code that depends on large C/C++\nlibraries, and is carefully designed so code can progressively be migrated to\nuse Nim's [`header`](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-header-pragma)\nand [`importcpp`](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-importcpp-pragma)\npragmas directly.\n\n## Recommended compiler switches\n\nThis project uses Nim's [ARC](https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc-in-nim.html)\nand C++17. It is well tested with non-trivial code using the Visual Studio\ncompiler on Windows. The recommended compiler switches are indicated at the top\nof the main [test](tests/tcinterop.nim) file.\n\n## Showcase\n\nPlease **see [tests](tests/)** for examples of most features. This section\nprovides an incomplete summary of the core functionality.\n\n### C++ Class interop\n\nSay you have the following C++ class:\n\n```cpp\n// simple.hpp\n\nclass CppClass1\n{\npublic:\n    int field1 = 1;\n\n    int method1(int arg)\n    {\n        return 1 + arg;\n    }\n};\n```\n\nYou simply need to declare the C++ type and the source file it resides in:\n\n```nim\n# simple.nim\n\nimport cinterop/decls\n\ncsource \"simple.hpp\":\n  type CppClass1* = object of CClass\n```\n\nand then you can access the fields and methods of that type:\n\n```nim\n# main.nim\n\nimport cinterop/exprs\n\nvar instance1 = CppClass1.init()\n\necho cexpr[cint]^instance1.field1 # prints \"1\"\n\ncexpr[cint]^instance1.field1 = 2\n\necho cexpr[cint]^instance1.method1(instance1.field1) # prints \"3\"\n```\n\nNotice that `cexpr[T]^` indicates the return type `T` of the whole expression,\nand only needs to be used at the beginning. This means that types for members do\nnot need to be declared, as long as the type of the variable whose members are\naccessed is known.\n\n### Void returns\n\nFor expressions that evaluate to `void`, one can use the `cexpr^` invocation,\nwhich is shorthand for `cexpr[void]^`:\n\n```nim\ncexpr^instance1.method1(0)\n```\n\n### Type inference\n\nIf the type of a return value does not need to be known but is used in an\noperation, one can use the `cauto^` invocation like so:\n\n```nim\ncauto^instance1.field1 += 2\n```\n\n### Binary operations\n\nA `cexpr[T]^` invocation can appear on either side of a binary operation.\n`cauto^` can only be used on the right-hand side unless the left-hand side is\nalso a `cauto^` invocation. Examples:\n\n```nim\ncexpr[cint]^instance1.field1 += cexpr[cint]^instance1.field1\n\ncauto^instance1.field1 += cexpr[cint]^instance1.field1 # same as above\n\ncauto^instance1.field1 += cauto^instance1.field1 # same as above\n```\n\n### Free function interop\n\nThe following technique can be used for libraries with lots of functions that\ndon't hang off of classes:\n\n```nim\n# glfw3.nim\n\ncsource \u0026\"{GLFW}/glfw3.h\": # header file\n  type cglfw* {.cgen:\"(glfw$1(@))\".} = object of CClass\n```\n\n```nim\n# canvas.nim\n...\ncauto^cglfw.GetMouseButton(self.window, button) == 1\n# generates something like `glfwGetMouseButton(self.window, button) == 1`\n...\n```\n\n`cglfw` here serves as a namespace that is not visible in C++. The `cgen` pragma\ntells the compiler how `cglfw.GetMouseButton(self.window, button)` should be\ngenerated and has the same semantics as Nim's `importcpp` pragma.\n\n### Enums\n\nFor working with C/C++ enums, one can use the `cenum` pragma like so:\n\n```nim\ntype CPP_ENUM* {.cenum.} = object\n```\n\nAlthough enums can be emulated using `CClass` and static methods, `cenum`\nprovides better checking of enum semantics and produces better C/C++ code for\nenums. By default, enum field access results in an expansion similar to the\nfollowing:\n\n```nim\nlet enumValue = cauto^CPP_ENUM.MEMBER_1\n# generates `CPP_ENUM enumValue = CPP_ENUM_MEMBER_1`\n```\n\nCustom code generation for enums can be achieved using `cgen` as well.\n\n## Gotchas\n\n### Unary operations\n\nUnary operators cannot be used with `cexpr[T]^` and `cauto^` invocations\nwithout using parentheses:\n\n```nim\n# echo -cauto^instance1.field1 # error\n\necho -(cauto^instance1.field1) # compiles\n```\n\nThere is a [proposal](https://github.com/nim-lang/RFCs/issues/415) to avoid this\nissue and enable a more natural implementation of `cexpr[T]^`.\n\n### Initialization\n\n`cauto^` can be used on the right-hand side of an initialization, but doing so\nmay cause backend compile errors, especially if done at the global scope:\n\n```nim\nlet value = cauto^instance1.field1 # C++ backend may produce an error here\n```\n\nIf this issue is encountered, the workaround is to explicitly specify the type:\n\n```nim\nlet value = cexpr[cint]^instance1.field1\n```\n\nOther issues are documented in the tests.\n\n## Installing\n\nThanks to [@mantielero](https://github.com/mantielero) for adding initial\nsupport for nimble! The package can be installed by following the nimble\ninstructions [here](https://github.com/nim-lang/nimble#nimble-install).\n\n## Usage\n\nTypical usage is to import `cinterop/decls` in modules that declare C/C++ types,\nand to import those modules along with `cinterop/exprs` to make use of them in\nother modules.\n\n## Contributing\n\nThis project is maintained during my free time, and serves as a tool for a game\nengine I am writing after work hours. Contributions are welcome, and I will\nmerge them immediately if they serve to keep the project robust, simple, and\nmaintainable.\n\n**Cheers and happy coding!** 🍺\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fn0bra1n3r%2Fcinterop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fn0bra1n3r%2Fcinterop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fn0bra1n3r%2Fcinterop/lists"}