I've a compiled static library, but don't have the code of it. I know the library embeds lots of files on compilation and looks something like this:
//files.zig
const std = @import("std");
pub const file_paths = [_][]const u8{
"www/x/in.txt",
"www/emd.txt",
"www/index.html",
"www/e2.txt",
};
const EmbeddedFile = struct {
path: []const u8,
content: []const u8,
};
pub const embedded_files = blk: {
var fs: [file_paths.len]EmbeddedFile = undefined;
for (file_paths) |file_path, i| {
const embedded_file = EmbeddedFile{
.path = file_path,
.content = @embedFile(file_path),
};
fs[i] = embedded_file;
}
break :blk fs;
};
How can I use the library in my app? For example, how can I display the content of the file www/index.html
that is embeded in this library, from my app code.
If you want to use internals of a static library, you have to link against it firstly. You can do it by using Zig build system or manually.
For the first option you have to edit build.zig
file in the root of your project by adding addObjectFile("path")
to your executable object.
Here is the build file for zig v0.10.1
which is automatically generated by zig init-exe
command with exe.addObjectFile
function call added
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("test_exe", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
exe.addObjectFile("path/to/file.a(or .lib if on Windows)"); // linking the executable against a "file.a" static library.
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const exe_tests = b.addTest("src/main.zig");
exe_tests.setTarget(target);
exe_tests.setBuildMode(mode);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&exe_tests.step);
}
To link the library with only using Zig compiler you just need to add it's path into the list of targets like this:
zig build-exe src/main.zig path/to/the/lib.a
To use exported functions/variables you have to declare them with the extern
keyword. If you want to import something that uses non-primitive type, you should define it yourself.
Usually, library developers provide header(for C) or package(for Zig) files if they want to distribute their library as a static or shared archive. These files contain all exported functions, variables, types, because a common user of a big library don't know anything about what is exported without them.
const std = @import("std");
const EmbeddedFile = struct {
path: [*:0]const u8,
content: [*:0]const u8,
};
// Notice the extern keyword.
// It tells the compiler embedded_files is taken from a shared or static library.
extern const embedded_files: [4]EmbeddedFile;
pub fn main() !void {
for (embedded_files) |file| {
std.debug.print("file:\t\t{s}\n", .{file.path});
std.debug.print("content:\t{s}\n", .{file.content});
}
}
Output:
file: www/x/in.txt
content: text
file: www/emd.txt
content: text
file: www/index.html
content: text
file: www/e2.txt
content: text
The code you provided can't represent the actual internals of the library, because:
So I assumed the library looks like this:
const std = @import("std");
const file_paths = [_][]const u8{
"www/x/in.txt",
"www/emd.txt",
"www/index.html",
"www/e2.txt",
};
const EmbeddedFile = extern struct {
path: [*:0]const u8,
content: [*:0]const u8,
};
export const embedded_files = blk: {
var fs: [file_paths.len]EmbeddedFile = undefined;
for (file_paths) |file_path, i| {
const embedded_file = EmbeddedFile{
.path = file_path[0.. :0],
.content = @embedFile(file_path)[0.. :0],
};
fs[i] = embedded_file;
}
break :blk fs;
};