{"id":15731729,"url":"https://github.com/flyx/libyaml_constructor","last_synced_at":"2025-11-04T03:04:46.188Z","repository":{"id":140903866,"uuid":"129613853","full_name":"flyx/libyaml_constructor","owner":"flyx","description":"Code generator to load YAML into C types","archived":false,"fork":false,"pushed_at":"2019-01-08T21:38:12.000Z","size":258,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-26T18:24:38.379Z","etag":null,"topics":["c","deserialization","libyaml","yaml"],"latest_commit_sha":null,"homepage":null,"language":"C","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/flyx.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"copying.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":"2018-04-15T13:39:52.000Z","updated_at":"2024-10-28T09:13:46.000Z","dependencies_parsed_at":"2023-06-01T10:30:47.195Z","dependency_job_id":null,"html_url":"https://github.com/flyx/libyaml_constructor","commit_stats":{"total_commits":76,"total_committers":1,"mean_commits":76.0,"dds":0.0,"last_synced_commit":"00d5bb5342859d1ea7f754bde3c18da6c20f530f"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyx%2Flibyaml_constructor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyx%2Flibyaml_constructor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyx%2Flibyaml_constructor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyx%2Flibyaml_constructor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flyx","download_url":"https://codeload.github.com/flyx/libyaml_constructor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243341406,"owners_count":20275866,"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":["c","deserialization","libyaml","yaml"],"created_at":"2024-10-04T00:04:40.505Z","updated_at":"2025-11-04T03:04:46.140Z","avatar_url":"https://github.com/flyx.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libyaml_constructor\n\n**libyaml_constructor** is a tool and library that loads a YAML document into\nnative C types. It consists of the *generator* tool that takes a C header and\ngenerates the code for loading, and the *runtime* library that provides common\nfunctionality used by the generated code.\n\nThe *constructor* depends on the excellent [libclang][1] for parsing the\ngiven header. The generated code and the *runtime* (quite obviously) depend on\n[libyaml][4].\n\n## Status\n\nI develop this project as part of a larger one. That means that it\nprobably will not get complete support for every feature the C type\nsystem has in the forseeable future. I only add features when needed.\n\nSince this project is in development, do not expect it to work smoothly\nand be wary about its generated code, especially concerning memory leaks\nwhen the YAML fails to load.\n\nList of stuff that currently works:\n\n * integer and unsigned types (`short`, `int`, `long`, `long long`,\n   `unsigned char`, `unsigned short`, `unsigned`, `unsigned long`,\n   `unsigned long long`)\n * floating point types (`float`, `double`, `long double`)\n * `char` (interpreted as ASCII-character)\n * `bool` (taking the literals `true` and `false`)\n * `struct` with fields containing anything from this list\n * `enum` at top-level\n * `char*` as string or optional string\n * pointers to anything on this list apart from pointers, possibly optional\n * dynamic lists (see below)\n * [tagged unions][2] (see below)\n * having reference to line and column in error messages\n\nList of stuff that currently does not work:\n\n * serializing back to YAML\n * anonymous structs inside structs\n * reading the documentation (there is none apart from this Readme)\n\n**The documentation in this readme is usually outdated.**\n\n## Usage\n\n    yaml_constructor_generator [options] file\n      options:\n        -o directory       writes output files to $directory (default: .)\n        -r name            expects the root type to be named $name.\n                           default: \"root\"\n        -n name            names output files $name.h and $name.c .\n                           default: ${file without ext}_loading.{h,c}.\n\nIn your code, you need to *annotate* certain structures so that\nlibyaml_constructor knows your intention. You annotate a type or field by\nadding a comment in front of it which has `!` as first character in the\ncomment content (i.e. it starts with either `//!` or `/*!`). The string\nfollowing the `!` is the annotation until the next space. Content after\nthat space until the following space is an optional parameter.\n\nThe following annotations exist:\n\n * `string`: for `char*` fields. Tells the generator to generate a\n   (heap-allocated) null-terminated string into this field.\n * `list`: for structs containing a `data` pointer as well as two\n   unsigned values `count` and `capacity`. The generator will treat the\n   annotated struct as dynamically growing list of items.\n * `tagged`: for structs containing exactly two items; the first one\n   being an `enum` value and the second one being a `union`. This will\n   cause the struct to be treated as [tagged union][2]. The YAML input\n   value will be required to have a *local tag* matching the `repr` of\n   one of the enum's values, prepended by a `!` (to be a local tag). The\n   YAML value will then be deserialized into the union field with the\n   same index as the specified enum value. If there are more enum values\n   than union fields, the surplus values will have no content and must\n   be given in the YAML as empty string with the respective local tag.\n * `repr`: takes a parameter. Currently only supported for enum values.\n   Enum value will be loaded from the representation given as parameter.\n   This means that the spelling of the enum value in the code will *not*\n   be accepted.\n * `optional`: for fields of pointer types. Tells the generator that this field\n   may be omitted in the YAML, in which case it will be `NULL` after loading.\n * `optional_string`: for `char*` fields, works like `optional` but if given,\n   parses into a null-terminated string.\n * `ignored`: for types that should be ignored while parsing the header\n   file. Mind that these types may not be used for fields of any type\n   for which deserialization code should be generated.\n * `custom`: for types that have user-defined constructors and\n   deallocators. The user-defined functions must be declared in the\n   header and must have the same name and signature that would be\n   generated if the functions were to be auto-generated.\n * `default`: for fields of value types. Tells the generator that this\n   field may be omitted in the YAML, in which case it will have a\n   default value depending on the type. Default values are 0 for all\n   signed and unsigned integer types as well as `enum` types, and an empty\n   list for struct types tagged with `list`. Other types may not use the\n   `default` tag.\n\n## Building\n\nTo build `libyaml_constructor_generator`, you need:\n\n * A **C** compiler. **libyaml_constructor** is tested and known to work with\n   GCC, LLVM/Clang and Visual Studio.\n * [CMake][3], Version 3.10 or later\n * [libclang][1]. On macOS, you currently need to install Xcode which bundles\n   libclang (not just the command line utilities which do not) and use\n   `xcode-select` to select it as the active toolchain. You also need to\n   install headers into `/usr/include` via the package located at\n   `/Library/Developer/CommandLineTools/Packages`. This is required for\n   libclang to be able to parse your code. *This may change in the future, but\n   I currently have other worries*.\n\nThe tests, as any generated code, also depend on [libyaml][4]\n(quite obviously).\n\n### Instructions for Windows\n\nDownload the latest [Visual Studio IDE][6] (Community Edition unless you are in\npossession of a license) and install it. Download the latest\n[pre-built LLVM binaries][5] for Windows and execute the installer. Download\nthe latest [CMake][3] installer and execute it.\n\nSince you are already in possession of all tools required to compile libyaml,\nI suggest you build it yourself: Get the latest [LibYaml release][7] and unpack\nit somewhere. Ignore the build instructions on the page; we will use CMake to\nbuild it instead. Start the CMake GUI, configure the source code to be the\ndirectory you unpacked the files into, and the binary folder to something like\n`cmake-vs` inside the source folder. Click *Configure*, *Generate* and then\n*Open Project*. Visual Studio should launch. Select the *Release*\nconfiguration, right-Click on the *yaml* project and select *Build*. This\nshould give you a *yaml.dll* in `cmake-vs/Release`.\n\nNow, to compile `yaml_constructor_generator`, go back to the CMake GUI and\nselect the `libyaml_constructor` folder as source folder and a subfolder\n`cmake-vs` as subfolder. We will need to add some entries to the configuration\nso that CMake finds all dependencies:\n\n * Add a `PATH` variable named `LibClang_ROOT` and make it point to your LLVM\n   installation's root folder (e.g. `C:\\LLVM`).\n * Add a `PATH` variable named `LibYaml_ROOT` and make it point to the folder\n   you unpacked the libyaml sources to.\n * Add a `PATH` variable named `LibYaml_LIBDIR` and make it point to the folder\n   that holds the `yaml.dll` (e.g. `${LibYaml_ROOT}/cmake-vs/Release`).\n\nAfter that, you should be able to *Configure* and *Generate* a Visual Studio\nproject. Open it, select the *Release* configuration and build the\n*yaml_constructor_generator* project. It generates the executable and places\nrequired dependencies (`libclang.dll`) in the output folder\n(`cmake-vs/Release`). You can now use it to generate code.\n\n## Example\n\nLet's assume we have some header file `simple.h` like this:\n\n```c\n#include \u003cstddef.h\u003e\n\n#ifndef _SIMPLE_H\n#define _SIMPLE_H\n\nenum gender_t {\n  //!repr male\n  MALE = 0,\n  //!repr female\n  FEMALE = 1,\n  //!repr other\n  OTHER = 2\n};\n\nstruct person {\n  //!string\n  char* name;\n  int age;\n  enum gender_t gender;\n};\n\n//!list\nstruct person_list {\n  struct person* data;\n  size_t count;\n  size_t capacity;\n};\n\nenum int_or_string_t {\n  //!repr int\n  INT_VALUE,\n  //!repr string\n  STRING_VALUE\n};\n\n//!tagged\nstruct int_or_string {\n  enum int_or_string_t type;\n  union {\n    int i;\n    //!string\n    char* s;\n  };\n};\n\nstruct root {\n  char symbol;\n  struct person_list people;\n  struct int_or_string foo;\n};\n\n#endif\n```\n\nTo autogenerate loading code, we execute this command:\n\n    yaml_constructor_generator simple.h\n\nWe do not need to give any options since our root type is named `root`\n(the default) and we want the generated files to be in the current\ndirectory. The command produces `simple_loading.h` and\n`simple_loading.c`.\n\nNow, having those, we write our main procedure:\n\n```c\n#include \"simple.h\"\n#include \u003csimple_loading.h\u003e\n\n#include \u003cyaml_loader.h\u003e\n\nstatic const char* input =\n    \"symbol: W\\n\"\n    \"people:\\n\"\n    \"  - name: Ada Lovelace\\n\"\n    \"    age: 36\\n\"\n    \"    gender: female\\n\"\n    \"  - name: Karl Koch\\n\"\n    \"    age: 27\\n\"\n    \"    gender: male\\n\"\n    \"  - name: Scrooge McDuck\\n\"\n    \"    age: 75\\n\"\n    \"    gender: other\\n\"\n    \"foo: !int 42\\n\";\n\nint main(int argc, char* argv[]) {\n  yaml_loader_t loader;\n  yaml_loader_init_string(\u0026loader, (const unsigned char*)input, strlen(input));\n  struct root data;\n  bool success = yaml_load_struct_root(\u0026data, \u0026loader);\n  if (!success) {\n    fprintf(stderr, \"error while loading YAML.\");\n    return 1;\n  } else {\n    printf(\"symbol = %c\\nPersons:\\n\", data.symbol);\n    for (size_t i = 0; i \u003c data.people.count; ++i) {\n      struct person* item = \u0026data.people.data[i];\n      printf(\"  %s, age %i\\n\", item-\u003ename, item-\u003eage);\n    }\n    yaml_loader_delete(\u0026loader);\n    free_one_struct__root(\u0026data);\n    return 0;\n  }\n}\n```\n\nExecuting it yields:\n\n    symbol = W\n    Persons:\n      Peter Pan, age 12\n      Karl Koch, age 27\n      Scrooge McDuck, age 75\n\n## Autogenerating Code with CMake\n\nFor an example, see [test/CMakeLists.txt](test/CMakeLists.txt). Link the target\nthat uses the generated code to the `yaml_constructor` target, which is the\nruntime.\n\nI suggest using git submodules or [git-subrepo][8] to use libyaml_constructor in\nyour project. That will allow you to reuse this project's CMake module to\nfind libyaml.\n\n## License\n\n[MIT](copying.txt)\n\n\n [1]: https://clang.llvm.org/doxygen/group__CINDEX.html\n [2]: https://en.wikipedia.org/wiki/Tagged_union\n [3]: https://cmake.org/\n [4]: https://pyyaml.org/wiki/LibYAML\n [5]: https://releases.llvm.org/download.html\n [6]: https://visualstudio.microsoft.com/\n [7]: https://pyyaml.org/wiki/LibYAML\n [8]: https://github.com/ingydotnet/git-subrepo","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyx%2Flibyaml_constructor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflyx%2Flibyaml_constructor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyx%2Flibyaml_constructor/lists"}