{"id":15068179,"url":"https://github.com/atilaneves/dpp","last_synced_at":"2025-04-06T12:07:25.310Z","repository":{"id":42349950,"uuid":"99037063","full_name":"atilaneves/dpp","owner":"atilaneves","description":"Directly include C headers in D source code","archived":false,"fork":false,"pushed_at":"2024-06-11T20:04:21.000Z","size":1556,"stargazers_count":235,"open_issues_count":86,"forks_count":31,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-30T11:07:04.503Z","etag":null,"topics":["clang","cpp","cpp17","d","dlang","dlanguage","libclang","translation"],"latest_commit_sha":null,"homepage":null,"language":"D","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/atilaneves.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2017-08-01T19:43:29.000Z","updated_at":"2025-03-27T16:38:40.000Z","dependencies_parsed_at":"2024-05-21T23:23:03.884Z","dependency_job_id":"6485b1e9-63fa-4186-8c42-3ae923ba04ab","html_url":"https://github.com/atilaneves/dpp","commit_stats":{"total_commits":1206,"total_committers":24,"mean_commits":50.25,"dds":"0.14925373134328357","last_synced_commit":"dc92324a29254aa2c932d524de735e4fbab4ae9e"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atilaneves%2Fdpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atilaneves%2Fdpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atilaneves%2Fdpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atilaneves%2Fdpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atilaneves","download_url":"https://codeload.github.com/atilaneves/dpp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247478318,"owners_count":20945266,"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":["clang","cpp","cpp17","d","dlang","dlanguage","libclang","translation"],"created_at":"2024-09-25T01:32:03.793Z","updated_at":"2025-04-06T12:07:25.284Z","avatar_url":"https://github.com/atilaneves.png","language":"D","readme":"d++ - #include C and C++ headers in D files\n====================================================\n\n[![CI](https://github.com/atilaneves/dpp/actions/workflows/d.yml/badge.svg)](https://github.com/atilaneves/dpp/actions/workflows/d.yml)\n[![Coverage](https://codecov.io/gh/atilaneves/dpp/branch/master/graph/badge.svg)](https://codecov.io/gh/atilaneves/dpp)\n[![Open on run.dlang.io](https://img.shields.io/badge/run.dlang.io-open-blue.svg)](https://run.dlang.io/is/JK0CAf)\n\nGoal\n----\n\nTo directly `#include` C and C++ headers in [D](https://dlang.org) files and have the same semantics and ease-of-use\nas if the file had been `#included` from C or C++ themselves. Warts and all, meaning that C `enum` declarations\nwill pollute the global namespace, just as it does \"back home\".\n\nThis work was supported by [Symmetry Investments](http://symmetryinvestments.com/).\n\nExample\n-------\n\n```c\n// c.h\n#ifndef C_H\n#define C_H\n\n#define FOO_ID(x) (x*3)\n\nint twice(int i);\n\n#endif\n```\n\n```c\n// c.c\nint twice(int i) { return i * 2; }\n```\n\n```d\n// foo.dpp\n#include \"c.h\"\nvoid main() {\n    import std.stdio;\n    writeln(twice(FOO_ID(5)));  // yes, it's using a C macro here!\n}\n```\n\nAt the shell:\n\n```\n$ gcc -c c.c\n$ d++ foo.dpp c.o\n$ ./foo\n$ 30\n```\n\n[![Open on run.dlang.io](https://img.shields.io/badge/run.dlang.io-open-blue.svg)](https://run.dlang.io/is/WwpvhT)\n\nC++ support\n-----------\n\nC++ support is currently limited. Including any header from the C++\nstandard library is unlikely to work.  Simpler headers might, the\nprobability rising with how similar the C++ dialect used is to\nC. Despite that, dpp currently does try to translate classes,\ntemplates and operator overloading. It's unlikely to work on\nproduction headers without judicious use of the `--ignore-cursor` and\n`--ignore-namespace` command-line options.  When using these, the user\ncan then define their own versions of problematic declarations such as\n`std::vector`.\n\nLimitations\n-----------\n\n* Only known to work on Linux with libclang versions 6 and up. It might work in different conditions.\n* When used on multiple files, there might be problems with duplicate definitions depending on imports.\n  It is recommended to put all `#include`s in one `.dpp` file and import the resulting D module.\n* Not currently able to translate Linux kernel headers.\n\nSuccess stories\n--------------\n\nKnown project headers whose translations produce D code that compiles:\n\n* nanomsg/nn.h, nanomsg/pubsub.h\n* curl/curl.h\n* stdio.h, stdlib.h\n* pthread.h\n* julia.h\n* xlsxwriter.h\n* libvirt/libvirt.h, libvirt/virterror.h\n* libzfs\n* openssl/ssl.h\n* imapfilter.h\n* libetpan/libetpan.h\n* Python.h\n\nCompilation however doesn't guarantee they work as expected and YMMV. Please consult the examples.\n\n\nCommand-line arguments\n----------------------\n\nIt is likely that the header or headers need `-I` flags to indicate paths to be searched,\nboth by this executable and by libclang itself. The `--include-path` option can be\nused for that, once for each such path.\n\nUse `-h` or `--help` to learn more.\n\n\nDetails\n-------\n\n`d++` is an executable that wraps a D compiler such as dmd (the default) so that D files with `#include`\ndirectives can be compiled.\n\nIt takes a `.dpp` file and outputs a valid D file that can be compiled. The original can't since D\nhas no preprocessor, so the `.dpp` file is \"quasi-D\", or \"D with #include directives\".\nThe only supported C preprocessor directive is `#include`.\n\nThe input `.dpp` file may also use C preprocessor macros defined in the file(s) it `#include`s, just as a C/C++\nprogram would (see the example above). It may not, however, define macros of its own.\n\n`d++` goes through the input file line-by-line, and upon encountering an `#include` directive, parses\nthe file to be included with libclang, loops over the definitions of data structures and functions\ntherein and expands in-place the relevant D translations. e.g. if a header contains:\n\n```c\nuint16_t foo(uint32_t a);\n```\n\nThe output file will contain:\n\n```d\nushort foo(uint a);\n```\n\nd++ will also enclose each one of these original `#include` directives with either\n`extern(C) {}` or `extern(C++) {}` depending on the header file name and/or command-line options.\n\nAs part of expanding the `#include`, and as well as translating declarations, d++ will also\ninsert text to define macros originally defined in the `#include`d translation unit so that these\nmacros can be used by the D program. The reason for this is that nearly every non-trivial\nC API requires the preprocessor to use properly. It is possible to mimic this usage in D\nwith enums and CTFE, but the result is not guaranteed to be the same. The only way to use a\nC or C++ API as it was intended is by leveraging the preprocessor.\n\nTrivial literal macros however(e.g. `#define THE_ANSWER 42`) are translated as\nD enums.\n\nAs a final pass before writing the output D file, d++ will run the C\npreprocessor (currently the cpp binary installed on the system) on the\nintermediary result of expanding all the `#include` directives so that\nany used macros are expanded, and the result is a D file that can be compiled.\n\nIn this fashion a user can write code that's not-quite-D-but-nearly that can \"natively\"\ncall into a C/C++ API by `#include`ing the appropriate header(s).\n\n\nTranslation notes\n----------------\n\n### enum\n\nFor convenience, this declaration:\n\n```c\nenum Enum { foo, bar, baz }\n```\n\nWill generate this translation:\n\n```d\nenum Enum { foo, bar, baz }\nenum foo = Enum.foo;\nenum bar = Enum.bar;\nenum baz = Enum.baz;\n```\n\nThis is to mimic C semantics with regards to the global namespace whilst also allowing\none to, say, reflect on the enum type.\n\n\n### Renaming enums\n\nThere is the ability to rename C enums. With the following C definition:\n\n```c\nenum FancyWidget { Widget_foo,  Widget_bar }\n```\n\nThen adding this to your .dpp file after the `#include` directive:\n\n```d\nmixin dpp.EnumD!(\"Widget\",      // the name of the new D enum\n                 FancyWidget,   // the name of the original C enum\n                 \"Widget_\");    // the prefix to cut out\n```\n\nwill yield this translation:\n\n```d\nenum Widget { foo, bar }\n```\n\n\n\n### Names of structs, enums and unions\n\nC has a different namespace for the aforementioned user-defined types. As such, this is legal C:\n\n```c\nstruct foo { int i; };\nextern int foo;\n```\n\nThe D translations just use the short name for these aggregates, and if there is a name collision\nwith a variable or function, the latter two get renamed and have a `pragma(mangle)` added to\navoid linker failures:\n\n\n```d\nstruct foo { int i; }\npragma(mangle, \"foo\") extern export __gshared int foo_;\n```\n\n### Functions or variables with a name that is a D keyword\n\nSimilary to name collisions with aggregates, they get an underscore\nappended and a `pragma(mangle)` added so they link:\n\n```c\nvoid debug(const char* msg);\n```\n\nBecomes:\n\n\n```d\npragma(mangle, \"debug\")\nvoid debug_(const(char)*);\n```\n\n\nBuild Instructions\n------------------\n```\ndub install dpp\n```\n\nAfter the instructions for your OS (see below), you can use this commands to run dpp:\n\n```\ndub run dpp -- yoursourcefilenamehere.dpp\n```\n\nNote: for a reproducible and cross-platform build environment, you can run [setup-cpp](https://github.com/aminya/setup-cpp) with `--llvm=11.0.0`. This will set up LLVM 11.0.0 and the proper environment variables.\n\n### Windows\n\nInstall [LLVM](https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/LLVM-12.0.0-win64.exe) into `C:\\Program Files\\LLVM\\`, making sure to tick the \"Add LLVM to the system PATH for all users\" option.\n\nIf `libclang.lib` was not found, put the `lib` folder of the llvm directory on the PATH.\n\n### Linux\n\nIf `libclang` is not installed, install `libclang-10-dev` with apt: `sudo apt-get install -y -qq libclang-10-dev`\n\nIf `libclang.so` was not found, link it using the following command (adjust the installation path and the llvm version):\n```\nsudo ln -s path_to_llvm/lib/libclang-12.so.1 /lib/x86_64-linux-gnu/libclang.so\n```\n\n### MacOS\n\nIf using an external LLVM installation, add these to your `~/.bash_profile`\n\n```bash\nLLVM_PATH=\"/usr/local/opt/llvm/\" # or any other path\nLLVM_VERSION=\"11.0.0\"\nexport PATH=\"$LLVM_PATH:$PATH\"\nexport SDKROOT=$(xcrun --sdk macosx --show-sdk-path)\nexport LD_LIBRARY_PATH=\"$LLVM_PATH/lib/:$LD_LIBRARY_PATH\"\nexport DYLD_LIBRARY_PATH=\"$LLVM_PATH/lib/:$DYLD_LIBRARY_PATH\"\nexport CPATH=\"$LLVM_PATH/lib/clang/$LLVM_VERSION/include/\"\nexport LDFLAGS=\"-L$LLVM_PATH/lib\"\nexport CPPFLAGS=\"-I$LLVM_PATH/include\"\nexport CC=\"$LLVM_PATH/bin/clang\"\nexport CXX=\"$LLVM_PATH/bin/clang++\"\n```\n\n(adjust the clang version and the external llvm installation path.)\n\nThen run `source ~/.bash_profile`\n\nIf `libclang.dylib` was not found, link it using the following command (adjust the installation path):\n```\nln -s path_to_llvm/lib/libclang.dylib /usr/local/opt/llvm/lib/libclang.dylib\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatilaneves%2Fdpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatilaneves%2Fdpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatilaneves%2Fdpp/lists"}