Need help using a C library in zig - zig

I am trying to port the microUI library from C into zig.
I have tried using this port attempt https://gitdab.com/luna/zig-microui as a guide post, but it does not seem to work.
Here is a breakdown of my attempt so far:
MicroUI is a very simple program, consisting of one .h file and one .c file. both of these files are located in the root of my project under the folder "./microui".
My build.zig:
const std = #import("std");
const c_args = [_][]const u8{
"-Wall",
"-std=c11",
"-pedantic",
// prevent sigill
"-fno-sanitize=undefined",
};
pub fn build(b: *std.build.Builder) void {
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const lib = b.addStaticLibrary("ZigMicroUI", "src/main.zig");
lib.linkSystemLibrary("c");
lib.linkLibC();
lib.addIncludeDir("./microui");
lib.addCSourceFile("microui/microui.c", &c_args);
lib.setBuildMode(mode);
lib.install();
var main_tests = b.addTest("src/main.zig");
main_tests.setBuildMode(mode);
const test_step = b.step("test", "Run library tests");
test_step.dependOn(&main_tests.step);
}
c.zig:
pub usingnamespace #cImport({
#cInclude("microui.h");
});
Relevant part of main.zig:
const std = #import("std");
const testing = std.testing;
const c = #import("c.zig");
export fn begin_window() void {
const ctx: c.mu_Context = null;
}
Output from 'zig build test':
.\src\c.zig:1:20: error: C import failed
pub usingnamespace #cImport({
^
.\src\c.zig:1:20: note: libc headers not available; compilation does not link against libc
pub usingnamespace #cImport({
^
.\zig-cache\o\013eb3e1efd6fe219480e321f33592ae\cimport.h:1:10: note: 'microui.h' file not found
#include <microui.h>
^
.\src\main.zig:6:16: error: container 'c' has no member called 'mu_Context'
const ctx: c.mu_Context = null;
I feel like this has to be something small that I'm missing if anyone can help.

You have to add the configuration to main_tests too:
main_tests.linkLibC();
main_tests.addIncludeDir("microui");
main_tests.addCSourceFile("microui/microui.c", &c_args);
Then zig build test will work.

Related

WebAssembly.instantiate fails when wasm file was compiled with `clang++`, but works with `clang`

When C/C++ .wasm code is compiled with clang (C) - it loads in Chrome and works well, but when with clang++ (C++) - wasm load fails with error (in JS console):
Uncaught (in promise) LinkError: WebAssembly.instantiate(): Import #1 module="wasi_snapshot_preview1" function="fd_close" error: function import requires a callable
Why?
WASM compile arguments:
"clang", <=== I only changed this to "clang++" - and it fails
"-O0",
// "-std=c++14",
"--target=wasm32-unknown-wasi",
"--sysroot C:\\OpenGL\\wasi-sdk-11.0-mingw.tar\\wasi-sdk-11.0\\share\\wasi-sysroot",
"-fno-exceptions",
"-nostartfiles",
"-Wl,--import-memory",
"-Wl,--no-entry",
"-Wl,--export-all",
"-o templates/my-app/public/hello_wasm.wasm",
"wasm/hello_wasm.cpp"
JS wasm load code:
const response = await fetch("./hello_wasm.wasm");
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {
env: { memory: this.memory },
},
});
this.instance = instance;
console.log("c" + instance);
})();
hello_wasm.cpp (compilation was without an error):
#include <math.h>
// extern "C"
// {
int int_sqrt(int x)
{
return sqrt(x);
};
float *run_sin(float x[], int n)
{
// float *a = new float[n];
float *a = (float *)malloc(sizeof(float) * n);
for (int i = 0; i < n; i++)
{
a[i] = x[i] * 2;
}
return a;
}
LLVM v10
I use wasi sysroot from https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-mingw.tar.gz
Also discussing this issue here https://github.com/WebAssembly/wasi-sdk/issues/145
In order to run a WASI binary on the web you need to provide an implementation of the WASI APIs. The web platform does not natively support WASI. There are some polyfills out there that try to emulate some/all of the WASI APIs which might work for your case.

Ocaml : segfault at GC when using a custom block containing a C pointer

I am trying to create a binding between a C library and an Ocaml program. I have encountered a problem when interfacing with the Gc.
I made a small program to duplicate my problem.
The objective is to pass a custom_block allocated in the C program and containing a pointer on a C structure to the main program in Ocaml.
Then, I am trying to use it (just printing a value in the example) before cleaning (I force a call to the GC).
In the main program below in ocaml, I can either comment the line "my_print_block" or the line "Gc.compact()" and everything works fine.The address of the pointer is correct, I can print the value and the destructor is called to free the C allocated pointer.
But when the two are activated, I get a segmentation fault.
Mail.ml
type ptr
external create_block: String.t -> ptr = "create_block"
external print_block: ptr -> unit = "print_block"
let my_print_block x :unit =
print_block x;
()
let main () =
let z = create_block "2.4" in
let _ = my_print_block z in
let () = Gc.compact () in
()
let _ = main ()
Interface.c
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/custom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct foo
{
float x;
};
void local_destroy(value v)
{
struct foo* p = *((struct foo**)Data_custom_val(v));
printf( "freeing p now (%p)\n with *p=%f \n", p, p->x );
fflush(stdout);
free(p);
}
static struct custom_operations ops = {
"ufpa custom_operations",
local_destroy,
custom_compare_default, //default function, should not be used
custom_hash_default, //default function, should not be used
custom_serialize_default, //default function, should not be used
custom_deserialize_default, //default function, should not be used
custom_compare_ext_default //default function, should not be used
};
void print_block(value type_str)
{
CAMLparam1(type_str);
struct foo* p = *( (struct foo**)Data_custom_val(type_str));
printf("value float = %f\n", p->x);
}
CAMLprim value create_block(value type_str)
{
CAMLparam1(type_str);
//retrieving str and creating a float value
char* fval = String_val(type_str);
float val = atof(fval);
//creating and allocating a custom_block
CAMLlocal1(res);
res = alloc_custom(&ops, sizeof(struct foo*), 10, 100);
//creating and allocating a struct pointer
struct foo* ptr = malloc(sizeof(struct foo));
printf("allocating : %p\n", ptr);
ptr->x = val;
//copying the pointer itself in the custom block
memcpy(Data_custom_val(res), &ptr, sizeof(struct foo*));
CAMLreturn(res);
}
Makefile
main.native: interface.c main.ml
rm -rf _build
rm -f main.native main.byte
ocamlbuild -cflags -g interface.o
ocamlbuild -lflag -custom -cflags -g -lflags -g main.byte -lflags interface.o
#ocamlbuild -cflags -g -lflags -g main.native -lflags interface.o
With ocamldebug, the program seems to crash on my_print_block but I wasn't able to extract more sense from the trace.
With gdb, the error is located in the Gc
#0 0x000000000040433d in caml_oldify_one ()
#1 0x0000000000406060 in caml_oldify_local_roots ()
#2 0x000000000040470f in caml_empty_minor_heap ()
#3 0x00000000004141ca in caml_gc_compaction ()
#4 0x000000000041bfd0 in caml_interprete ()
#5 0x000000000041df48 in caml_main ()
#6 0x000000000040234c in main ()
I have seen several examples and I have read the documentation about C bindings at https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html but I couldn't figure what am I doing wrong. I am using ocaml version4.04.0+flambda
Thank you for your assistance
Your print_block function uses CAMLparam1() so it should return with CAMLreturn0. I'm not sure this is your problem, it's just something I noticed. But it might be the problem.

My lua script load .so library, how can I write the host program with Lua 5.2?

I searched and tried for days. The problem is this:
I wrote a script which load a shared library locker.so, it runs well with lua interpretor, but I can not write out the correct host program.
My lua script load_so.lua is very simple:
locker = require("locker")
print(type(locker))
for k, v in pairs(locker) do
print(k, v)
end
My host program is:
int main(int argc, const char *argv[])
{
lua_State * L = luaL_newstate();
luaL_openlibs(L);
if (luaL_dofile(L, "load_so.lua") != 0) {
fprintf(stderr, "luaL_dofile error: %s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
return 0;
}
When I run my host program, error print out:
luaL_dofile error: error loading module 'locker' from file './locker.so':
./locker.so: undefined symbol: lua_pushstring
And the locker.c:
static int elock_get(lua_State * L) {...}
static int elock_set(lua_State * L) {...}
static const struct luaL_Reg lockerlib[] = {
{"get", elock_get},
{"set", elock_set},
{NULL, NULL}
};
int luaopen_locker(lua_State *L)
{
//luaL_newlib(L, lockerlib);
//lua_pushvalue(L, -1);
//lua_setglobal(L, LOCKER_LIBNAME);
//set_info(L);
luaL_newlibtable(L, lockerlib);
luaL_setfuncs(L, lockerlib, 0);
return 1;
}
Most articles, books, questions shows how to do it in Lua 5.1, and yes, the program runs correctly in Lua 5.1. But how can I make it support Lua 5.2, and why?
P.S: I don't want to load the library in my C host program like luaL_requiref(L, "locker", luaopen_locker, 1), because I don't know which .so library will load in Lua script.
Thanks.
In Linux, if you're linking liblua.a statically into your main program, you need to use -Wl,-E when linking to export the Lua API symbols; this is how the standard command line interpreter is built.

Using dynamic library loaded by LC_LOAD_DYLIB to interpose C functions

Firstly, what I want to do is to intercept an arbitrary standard C function (like fopen, read, write, malloc, ...) of an iOS application.
I have a libtest.dylib with this code:
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
FILE *vg_fopen(const char * __restrict, const char * __restrict);
static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)vg_fopen, (void *)fopen },
};
FILE *vg_fopen(const char * __restrict path, const char * __restrict mode) {
printf("vg_fopen");
return fopen(path, mode);
}
After compiled the dylib, I go to the binary of the host iOS app and add an LC_LOAD_DYLIB to the end of the LC_LOAD_COMMANDS list and point it to #executable_path/libtest.dylib
What I expect is that it will override the implementation of fopen, and print "vg_fopen" whenever fopen is called. However, I do not get it, so the interposition might have been failed.
I'd like to know what might be the reason. This is for in-house development for learning purpose only, so please don't mention about the impact or warn me about inappropriate use.
Thanks in advance.
From the dyld source:
// link any inserted libraries
// do this after linking main executable so that any dylibs pulled in by inserted
// dylibs (e.g. libSystem) will not be in front of dylibs the program uses
if ( sInsertedDylibCount > 0 ) {
for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
ImageLoader* image = sAllImages[i+1];
link(image, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
// only INSERTED libraries can interpose
image->registerInterposing();
}
}
So no, only libraries inserted via DYLD_INSERT_LIBRARIES have their interposing applied.

Network stats gatherer (loadable kernel module) isn't working?

I'm kinda new to linux kernel modules and I'm trying to write my own module that gives me some statistics about a device ( the NIC here).
although I'm using kernel 2.6.35 and I've included linux/netdevices, compiling keeps saying that the function ndo_get_stats is implicitly declared. can anyone tell me what's going on ?
here's the module, simple I know,
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/netdevice.h> /* Needed for netdevice*/
static int __init hello_start(void)
{
struct net_device *dev;
struct net_device_stats *devstats;
printk(KERN_INFO "Loading Stats module...\n");
printk(KERN_ALERT "Hello world\n");
dev = first_net_device(&init_net);
while (dev)
{
printk(KERN_INFO "found [%s] and it's [%d]\n", dev->name, dev->flags & IFF_UP);
printk(KERN_INFO "End of dev struct ... now starts the get_stats struct\n");
devstats = ndo_get_stats(dev);
printk(KERN_INFO "recive errors: [%li]\n transmission errors: [%li]\n number of collisions: [%li]", devstats->rx_errors , devstats->tx_errors, devstats->collisions);
dev = next_net_device(dev);
}
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_ALERT "Goodbye.\n");
}
module_init(hello_start);
module_exit(hello_end);

Resources