我正在学习如何使用终端创建库。是否有可能(我怀疑它可能不是)将资源(如图像,文本,API密钥等)放入静态链接的存档文件中,就像在NSBundle
中一样?我如何参考这些资源?
答案 0 :(得分:0)
您要做的是从二进制blob创建一个目标文件,以便能够链接到它。它需要是一个包含符号表的目标文件,该符号表至少包含一个符号(可能是blob的开头),因为你想要在程序的其余部分处理二进制数据的句柄
因为目标文件完全依赖于系统(有时甚至是编译器),所以没有直接实际执行此操作的可移植方法。例如,Linux曾经有过至少两种不同的目标文件格式。
最容易可移植(也许,甚至最简单)的方法:使用知道如何为开发环境构建目标文件的工具: C编译器。
编写自己的转换器,从二进制数据中创建C代码,如
const unsigned char blob[] = {0x0,0x22,.....};
然后编译并链接。不应该太难做,而是10分钟的工作。其他一切都完全不便携。
在可以使用GNU objcopy 的平台上,这可能是另一种做事方式。 (指定'binary'作为输入文件格式,将目标文件格式指定为输出目标。还需要使用“--add-symbol”添加blob的起始符号。)但我自己从未这样做过。
答案 1 :(得分:0)
在POSIX系统上,你有一个非常标准的shell sh
,四个非常有用的shell实用程序叫做rm
,printf
,od
和sed
假设您希望使用包含二进制文件foo.c
内容的const unsigned char blob[]
数组创建文件foo.bar
:
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,然后我们在该行前面添加另外三个空格(使其缩进四个空格)。
如果您不喜欢这种方法,您可以随时编写自己的实用程序来完成此操作。例如: #包括 #包括 #包括 #include
#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-ism是使用%zu
来扫描和打印size_t
。