我正在学习如何仅使用终端创建库。是否有可能(我怀疑可能不可能)将资源(例如图像、文本、API key 等)放入静态链接的存档文件中,就像在 NSBundle 中一样?我如何引用这些资源?
最佳答案
在 POSIX 系统上,您有一个几乎标准的 shell sh
,四个非常有用的 shell 实用程序,名为 rm
, printf
, od
,和sed
.
假设您希望使用包含二进制文件 foo.bar 内容的
:const unsigned char blob[]
数组创建文件 foo.c
export LANG=C LC_ALL=C
rm -f foo.c
printf 'const unsigned char blob[] = {\n' > foo.c
od -A n -t x1 foo.bar | sed -e 's| *\([0-9A-Fa-f][0-9A-Fa-f]\)| 0x\1U,|g; s|^| |' >> foo.c
printf '};\n' >> foo.c
第一行将语言环境设置为C
。这确保实用程序使用我们期望的格式,而不是某些本地化变体。
第二行删除可能存在的foo.c
。 (如果您将输出直接输出到现有文件而不附加到它,有些 shell 会提示。)如果文件还不存在,-f
会消除任何提示。
第三行和第五行将数组定义附加到 foo.c
文件中。
第四行使用od
实用程序将foo.bar
的内容输出为十六进制字节。我们使用 sed
在每个十六进制字节前面添加 0x
和附加 U,
使其变得漂亮且漂亮的 C,然后我们在前面添加额外的三个该行的空格(使其缩进四个空格)。
如果您不喜欢这种方法,您可以随时编写自己的实用程序来完成此操作。例如: #包括 #包括 #包括 #包括
#ifndef DEFAULT_VARNAME
#define DEFAULT_VARNAME "blob"
#endif
#ifndef DEFAULT_STORAGE
#define DEFAULT_STORAGE "const"
#endif
#ifndef DEFAULT_ATTRIBUTES
#define DEFAULT_ATTRIBUTES ""
#endif
#ifndef DEFAULT_INDENT
#define DEFAULT_INDENT " "
#endif
#ifndef DEFAULT_COLUMNS
#define DEFAULT_COLUMNS 16
#endif
int usage(const char *argv0)
{
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s [ OPTIONS ] file [ [ OPTIONS ] file .. ]\n", argv0);
fprintf(stderr, "\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -n %-10s Variable name\n", "'" DEFAULT_VARNAME "'");
fprintf(stderr, " -s %-10s Storage type\n", "'" DEFAULT_STORAGE "'");
fprintf(stderr, " -a %-10s Attributes\n", "'" DEFAULT_ATTRIBUTES "'");
fprintf(stderr, " -i %-10s Indentation\n", "'" DEFAULT_INDENT "'");
fprintf(stderr, " -c %-10d Bytes per line\n", (int)DEFAULT_COLUMNS);
fprintf(stderr, "\n");
fprintf(stderr, "This program will output the contents of the specified file(s)\n");
fprintf(stderr, "as C source code.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
const char *storage = DEFAULT_STORAGE;
const char *varname = DEFAULT_VARNAME;
const char *attributes = DEFAULT_ATTRIBUTES;
const char *indent = DEFAULT_INDENT;
size_t columns = DEFAULT_COLUMNS;
FILE *in;
size_t bytes;
int ch, arg;
char dummy;
if (argc < 2)
return usage(argv[0]);
arg = 1;
while (arg < argc) {
if (argv[arg][0] == '-') {
if (argv[arg][1] == 'n') {
if (argv[arg][2] != '\0') {
varname = argv[arg] + 2;
arg++;
continue;
} else
if (arg + 1 < argc) {
varname = argv[arg + 1];
arg += 2;
continue;
}
} else
if (argv[arg][1] == 's') {
if (argv[arg][2] != '\0') {
storage = argv[arg] + 2;
arg++;
continue;
} else
if (arg + 1 < argc) {
storage = argv[arg + 1];
arg += 2;
continue;
}
} else
if (argv[arg][1] == 'a') {
if (argv[arg][2] != '\0') {
attributes = argv[arg] + 2;
arg++;
continue;
} else
if (arg + 1 < argc) {
attributes = argv[arg + 1];
arg += 2;
continue;
}
} else
if (argv[arg][1] == 'i') {
if (argv[arg][2] != '\0') {
indent = argv[arg] + 2;
arg++;
continue;
} else
if (arg + 1 < argc) {
indent = argv[arg + 1];
arg += 2;
continue;
}
} else
if (argv[arg][1] == 'c') {
if (argv[arg][2] != '\0') {
if (sscanf(argv[arg] + 2, " %zu %c", &columns, &dummy) != 1 || columns < 1) {
fprintf(stderr, "%s: Invalid number of bytes per line.\n", argv[arg] + 2);
return EXIT_FAILURE;
}
arg++;
continue;
} else
if (arg + 1 < argc) {
if (sscanf(argv[arg+1], " %zu %c", &columns, &dummy) != 1 || columns < 1) {
fprintf(stderr, "%s: Invalid number of bytes per line.\n", argv[arg + 1]);
return EXIT_FAILURE;
}
arg += 2;
continue;
}
} else
if (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "--help"))
return usage(argv[0]);
}
in = fopen(argv[arg], "r");
if (!in) {
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
return EXIT_FAILURE;
}
printf("%s unsigned char %s[] %s= {", storage, varname, attributes);
bytes = 0;
while ((ch = getc(in)) != EOF)
if (bytes++ % columns)
printf(", %3u", (unsigned int)ch);
else
printf("\n%s%3u", indent, (unsigned int)ch);
printf("\n}; /* %zu bytes */\n\n", bytes);
if (ferror(in)) {
fclose(in);
fprintf(stderr, "%s: Read error.\n", argv[arg]);
return EXIT_FAILURE;
}
if (fclose(in)) {
fprintf(stderr, "%s: Delayed read error.\n", argv[arg]);
return EXIT_FAILURE;
}
if (fflush(stdout) || ferror(stdout)) {
fprintf(stderr, "Error writing to standard output.\n");
return EXIT_FAILURE;
}
arg++;
}
return EXIT_SUCCESS;
}
上述代码中唯一的 POSIX 主义是使用 %zu
扫描并打印 size_t
。
关于c - 在静态库中嵌入资源 - C/C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36098868/