logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

Embedding-files-in-C.md (2521B)


  1. ---
  2. date: 2018-05-29
  3. layout: post
  4. title: Embedding files in C programs with koio
  5. tags: [C, announcement]
  6. ---
  7. Quick blog post today to introduce a new tool I wrote:
  8. [koio](https://git.sr.ht/~sircmpwn/koio). This is a small tool which takes a
  9. list of files and embeds them in a C file. A library provides an fopen shim
  10. which checks the list of embedded files before resorting to the real filesystem.
  11. I made this tool for [chopsui](https://github.com/SirCmpwn/chopsui), where I
  12. eventually want to be able to bundle up sui markup, stylesheets, images, and so
  13. on in a statically linked chopsui program. Many projects have small tools which
  14. serve a similar purpose, but it was simple enough and useful enough that I chose
  15. to make something generic so it could be used on several projects.
  16. The usage is pretty simple. I can embed `ko_fopen.c` in a C file with this
  17. command:
  18. ```sh
  19. $ koio -o bundle.c ko_fopen.c://ko_fopen.c
  20. ```
  21. I can compile and link with `bundle.c` and do something like this:
  22. ```c
  23. #include <koio.h>
  24. void koio_load_assets(void);
  25. void koio_unload_assets(void);
  26. int main(int argc, char **argv) {
  27. koio_load_assets();
  28. FILE *src = ko_fopen("//ko_fopen.c", "r");
  29. int c;
  30. while ((c = fgetc(src)) != EOF) {
  31. putchar(c);
  32. }
  33. fclose(src);
  34. koio_unload_assets();
  35. return 0;
  36. }
  37. ```
  38. The generated `bundle.c` looks like this:
  39. ```c
  40. #include <koio.h>
  41. static struct {
  42. const char *path;
  43. size_t len;
  44. char *data;
  45. } files[] = {
  46. {
  47. .path = "//ko_fopen.c",
  48. .len = 408,
  49. .data =
  50. "#define _POSIX_C_SOURCE 200809L\n#include <errno.h>\n#include <stdlib.h>\n#inc"
  51. "lude <stdio.h>\n#include \"koio_private.h\"\n\nFILE *ko_fopen(const char *path"
  52. ", const char *mode) {\n\tstruct file_entry *entry = hashtable_get(&koio_vfs, p"
  53. "ath);\n\tif (entry) {\n\t\tif (mode[0] != 'r' || mode[1] != '\\0') {\n\t\t\ter"
  54. "rno = ENOTSUP;\n\t\t\treturn NULL;\n\t\t}\n\t\treturn fmemopen(entry->data, en"
  55. "try->len, \"r\");\n\t}\n\treturn fopen(path, mode);\n}\n",
  56. },
  57. };
  58. void koio_load_assets(void) {
  59. ko_add_file(files[0].path, files[0].data, files[0].len);
  60. }
  61. void koio_unload_assets(void) {
  62. ko_del_file(files[0].path);
  63. }
  64. ```
  65. A very simple tool, but one that I hope people will find useful. It's very
  66. lightweight:
  67. - 312 lines of C
  68. - /bin/koio is ~40 KiB statically linked to musl
  69. - libkoio.a is ~18 KiB
  70. - Only mandatory dependencies are POSIX 2008 and a C99 compiler
  71. - Only optional dependency is [scdoc](https://git.sr.ht/~sircmpwn/scdoc) for the
  72. manual, which is similarly lightweight
  73. Enjoy!