{"id":19142680,"url":"https://github.com/jgaa/mkres","last_synced_at":"2026-06-22T11:31:18.739Z","repository":{"id":209419722,"uuid":"723397473","full_name":"jgaa/mkres","owner":"jgaa","description":"Utility to embed files in C++ projects","archived":false,"fork":false,"pushed_at":"2025-05-23T06:32:45.000Z","size":30,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-23T07:55:19.147Z","etag":null,"topics":["code-generator","cpp20","embed-files"],"latest_commit_sha":null,"homepage":"","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/jgaa.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,"zenodo":null}},"created_at":"2023-11-25T14:40:55.000Z","updated_at":"2023-12-08T09:23:27.000Z","dependencies_parsed_at":"2024-11-09T07:30:30.916Z","dependency_job_id":"99fd9699-fb5b-41d9-8aac-e2220480ce00","html_url":"https://github.com/jgaa/mkres","commit_stats":null,"previous_names":["jgaa/mkres"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jgaa/mkres","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2Fmkres","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2Fmkres/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2Fmkres/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2Fmkres/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jgaa","download_url":"https://codeload.github.com/jgaa/mkres/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2Fmkres/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34647746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"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":["code-generator","cpp20","embed-files"],"created_at":"2024-11-09T07:28:06.574Z","updated_at":"2026-06-22T11:31:18.722Z","avatar_url":"https://github.com/jgaa.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mkres\nUtility to embed files in C++ projects\n\nIn some projects, I find it simpler to embed files in the binary,\nthen making an \"install\" procedure where files must be copied\nto some location on the destination system, and then found and\nused by the application.\n\nFor example; the [nsblast](https://github.com/jgaa/nsblast) name server\nhas an embedded HTTP server to support a REST API. I have added\nan option to also enable a swagger interface to this API. \n\nThe HTTP server fetches the JavaScript files\nand the rest of the swagger content, directly from memory\nin the server. The content is transformed from normal files\non the disk, to C++ code (mostly static arrays with data)\nby *mkres*.\n\nI have used various simpler versions of this program in various projects in the past.\nWhen I needed to add a React based Web User Interface to nsblast, I needed\nto recursively add files with non-predictable names - and support the target paths\nin the HTTP server. The files also become quite large, so I realized that I needed to\ncompress them. As a result, I created this new project to serve all my needs for\nembedded files in one code base.\n\n## What is does\n\n*Mkres* is a small command line utility written in C++ that can read one\nor more files on the local file system, and generate C++ code that\nembeds the content of the files to C++ code. It also provides a simple\ninterface (static C++ class) to lookup the content by name.\n\n**Features:**\n- Generate C++ code representing the content of one or more files as static const C++ data.\n- It accept files identified by their path on the command line.\n- It accept directories, which it will scan recursively and add the content with keys matching the file-names in the directory tree\n- Positive filter. You can specify a regex for files to add when adding directories.\n- Negative filter. You can specify a regex for files to exclude when working with directories.\n- Compression. You can use *gzip* compression for the content to save space. The content can be accessed by the application in it's compressed form, or automatically decompressed and used as strings.\n- You can specify C++ namespace (`--namespace`) for the generated code\n- You can specify the C++ class (`--name`) for the generated code\n\n\n## Requirements\n- C++20 compatible compiler. Tested with g++-13 and clang++-17.\n- zlib if compression is enabled (CMake option).\n- Boost library (program_options). The generated code does not require libboost.\n- Google Test if you compile with testing enabled (CMake option)\n\n## Usage:\n```\n./mkres -h\nmkres [options] input-file ...\nOptions:\n  -h [ --help ]                         Print help and exit\n  --version                             print version information and exit\n  -v [ --verbose ]                      Be verbose about what's being done\n  -r [ --recurse ]                      Recurse into directories\n  --filter arg                          Filter the file-names to embed (regex)\n  --exclude arg                         Exclude the the file-names to embed \n                                        (regex)\n  -d [ --destination ] arg (=\"out\")     Destination path/name. '.h' and '.cpp' \n                                        is added to the destination file names,\n                                        so just specify the name without \n                                        extention.\n  -c [ --compression ] arg (=none)      Compression to use. 'none' or 'gzip'. \n                                        If compressed, the application must \n                                        decompress the data before it can be \n                                        used.\n  -n [ --namespace ] arg (=mkres)       C++ Namespace to use for the embedded \n                                        resource(s)\n  -N [ --name ] arg (=EmbeddedResource) Resource-name. This is the static \n                                        constexpr name for the resource that \n                                        you call from your code.\n```\n\n\n## Example\n\nThis code is from nsblast.\n\n**Using mkres in a CMake project:**\n```cmake\nExternalProject_Add(mkres\n    PREFIX \"${EXTERNAL_PROJECTS_PREFIX}\"\n    GIT_REPOSITORY \"https://github.com/jgaa/mkres.git\"\n    GIT_TAG \"main\"\n    CMAKE_ARGS\n        -DCMAKE_INSTALL_PREFIX=${EXTERNAL_PROJECTS_INSTALL_PREFIX}\n        -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n        -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\n        -DCMAKE_GENERATOR='${CMAKE_GENERATOR}'\n        -DCMAKE_BUILD_TYPE='${CMAKE_BUILD_TYPE}'\n)\n\nset(MKRES \"${EXTERNAL_PROJECTS_PREFIX}/installed/bin/mkres\")\n```\n\n**Generating code swagger files**\n```cmake\nadd_custom_command(\n    COMMAND ${MKRES} --verbose --compression gzip --namespace nsblast::lib::embedded --name Swagger --destination swagger_res --exclude '.*\\\\.map' ${NSBLAST_ROOT}/swagger/*\n    DEPENDS ${NSBLAST_ROOT}/swagger/index.html ${NSBLAST_ROOT}/swagger/swagger.yaml mkres\n    OUTPUT swagger_res.cpp swagger_res.h\n    COMMENT \"Embedding swagger...\"\n    )\n\n    set(LIB_SWAGGER_FILES swagger_res.cpp swagger_res.h)\n\n    add_custom_target(swagger_res ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/swagger_res.cpp)\n\n```\n\n***The C++ interface to the embedded data***\n```C++ This is the generated header file\n// Generated by mkres version 0.1.0\n// See: https://github.com/jgaa/mkres\n\n#pragma once\n#include \u003ccstddef\u003e\n#include \u003cspan\u003e\n#include \u003cstring_view\u003e\n#include \u003cstring\u003e\nnamespace nsblast::lib::embedded {\n\nclass Swagger {\npublic:\n    struct Data {\n        const std::span\u003cconst std::byte\u003e data;\n        const size_t origLen{};\n\n        bool empty() const noexcept {\n            return data.empty();\n        }\n\n        // Gets the entire buffer. Decompresses the data if it's compressed.\n        std::string toString() const;\n    };\n\n    static const Data\u0026 get(std::string_view key) noexcept;\n\n    static constexpr bool isCompressed() noexcept {\n        return true;\n    }\n\n    static constexpr std::string_view compression() noexcept {\n        return \"gzip\";\n    }\n};\n} // namespace\n\n\n```\n\n**Using the swagger files in the embedded HTTP server**\n\nThis is real code. The interesting line in the template is:\n```C++\n    if (const auto\u0026 data = T::get(t); !data.empty()) {\n```\nHere the target the user has requested, for example `index.html` is\nlooked up in the generated code. \n\n```C++\n\ntemplate \u003ctypename T\u003e\nclass EmbeddedResHandler : public RequestHandler {\npublic:\n    explicit EmbeddedResHandler(std::string prefix)\n        : prefix_{std::move(prefix)} {}\n\n    Response onReqest(const Request\u0026 req) override {\n        auto t = std::string_view{req.target};\n\n        if (const auto\u0026 data = T::get(t); !data.empty()) {\n            std::filesystem::path served = prefix_;\n            served /= t;\n            return {200, \"OK\", data.toString(), served.string()};\n        }\n\n        return {404, \"Document not found\"};\n    }\n\nprivate:\n    const std::string prefix_;\n};\n\n....\n\n    const string_view swagger_path = \"/api/swagger\";\n    LOG_INFO \u003c\u003c \"Enabling Swagger at \" \u003c\u003c swagger_path;\n    \n    http_-\u003eaddRoute(swagger_path,\n                    make_shared\u003cEmbeddedResHandler\u003clib::embedded::Swagger\u003e\u003e(\"/api/swagger\"));\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgaa%2Fmkres","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjgaa%2Fmkres","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgaa%2Fmkres/lists"}