I don't know any C or Zig. But I'm trying some stuff out and I'm really impressed so far. I'm trying to run a web server in Zig using a C library "lwan". It works. But I'm having some trouble with making my handler function.
/mnt/c/www/zig/hello/main.zig:35:56: error: expected type '?extern fn([*c].cimport:4:14.struct_lwan_request, [*c].cimport:4:14.struct_lwan_response, ?*c_void) .cimport:4:14.enum_lwan_http_status', found '*const fn([*c].cimport:4:14.struct_lwan_request, [*c].cimport:4:14.struct_lwan_response, ?*c_void) .cimport:4:14.enum_lwan_http_status'
lwan.lwan_url_map{ .prefix = c"/", .handler = &hello_world },
^
/mnt/c/www/zig/hello/main.zig:35:56: note: pointer type child 'fn([*c].cimport:4:14.struct_lwan_request, [*c].cimport:4:14.struct_lwan_response, ?*c_void) .cimport:4:14.enum_lwan_http_status' cannot cast into pointer type child '.cimport:4:14.enum_lwan_http_status'
lwan.lwan_url_map{ .prefix = c"/", .handler = &hello_world },
^
zig-cache/o/7Ejdc3DFhsEkPBHu2o3vlPoREApH2LmQtGmS7KyNIBhIeaHdzX6DwQhyzd5U7Eo0/cimport.zig:1234:35: note: .cimport:4:14.enum_lwan_http_status declared here
pub const enum_lwan_http_status = extern enum {
So I'm guessing the type of my handler function is wrong. This is my handler:
fn hello_world(req: [*c]lwan.struct_lwan_request, res: [*c]lwan.struct_lwan_response, data: ?*c_void) lwan.enum_lwan_http_status {
return lwan.enum_lwan_http_status.HTTP_OK;
}
How do I change it to the type "?extern fn"?
I'm not even sure I'm doing something I'm supposed to do. If this isn't the purpose of Zig, just let me know.
One more thing: lwan creates handlers using this code:
#define LWAN_HANDLER_DECLARE(name_) \
static enum lwan_http_status lwan_handler_##name_( \
struct lwan_request *, struct lwan_response *, void *)
#define LWAN_HANDLER_DEFINE(name_) \
static const struct lwan_handler_info \
__attribute__((used, section(LWAN_SECTION_NAME(lwan_handler)))) \
lwan_handler_info_##name_ = {.name = #name_, \
.handler = lwan_handler_##name_}; \
static enum lwan_http_status lwan_handler_##name_( \
struct lwan_request *request __attribute__((unused)), \
struct lwan_response *response __attribute__((unused)), \
void *data __attribute__((unused)))
#define LWAN_HANDLER(name_) \
LWAN_HANDLER_DECLARE(name_); \
LWAN_HANDLER_DEFINE(name_)
And then uses this to pass the handler:
#define LWAN_HANDLER_REF(name_) lwan_handler_##name_
You need to make your handler function have the C calling convention by adding the word extern in front of it:
extern fn hello_world(req: [*c]lwan.struct_lwan_request, res: [*c]lwan.struct_lwan_response, data: ?*c_void) lwan.enum_lwan_http_status {
return lwan.enum_lwan_http_status.HTTP_OK;
}
See also this related issue, which may help clarify the syntax: https://github.com/ziglang/zig/issues/661
Related
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.
I am starting to make my own package manager and am starting to develop a dependency system.
The builfiles are written in lua, they look something like this:
package = {
name = "pfetch",
version = "0.6.0",
source = "https://github.com/dylanaraps/pfetch/archive/0.6.0.tar.gz",
git = false
}
dependencies = {
"some_dep",
"some_dep2"
}
function install()
quantum_install("pfetch", false)
end
Only problem,I have no idea how to convert
dependencies = {
"some_dep",
"some_dep2"
}
To a global c++ array: ["some_dep", "some_dep2"]
Anything in the list that's not valid as a string should be ignored.
Any good way to do this?
Thanks in advance
Note: I am using the C api to interface with lua in C++. I don't know whether Lua's errors use longjmp or C++ exceptions.
Based on the clarification in your comment, something like this will work for you:
#include <iostream>
#include <string>
#include <vector>
#include <lua5.3/lua.hpp>
std::vector<std::string> dependencies;
static int q64795651_set_dependencies(lua_State *L) {
dependencies.clear();
lua_settop(L, 1);
for(lua_Integer i = 1; lua_geti(L, 1, i) != LUA_TNIL; ++i) {
size_t len;
const char *str = lua_tolstring(L, 2, &len);
if(str) {
dependencies.push_back(std::string{str, len});
}
lua_settop(L, 1);
}
return 0;
}
static int q64795651_print_dependencies(lua_State *) {
for(const auto &dep : dependencies) {
std::cout << dep << std::endl;
}
return 0;
}
static const luaL_Reg q64795651lib[] = {
{"set_dependencies", q64795651_set_dependencies},
{"print_dependencies", q64795651_print_dependencies},
{nullptr, nullptr}
};
extern "C"
int luaopen_q64795651(lua_State *L) {
luaL_newlib(L, q64795651lib);
return 1;
}
Demo:
$ g++ -fPIC -shared q64795651.cpp -o q64795651.so
$ lua5.3
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
> q64795651 = require('q64795651')
> dependencies = {
>> "some_dep",
>> "some_dep2"
>> }
> q64795651.set_dependencies(dependencies)
> q64795651.print_dependencies()
some_dep
some_dep2
>
One important pitfall: since you're not sure if Lua is compiled to use longjmp or exceptions for its errors, you need to make sure that you don't have any automatic variables with destructors anywhere that a Lua error could happen. (This is already the case in the code in my answer; just make sure you don't accidentally add any such places when incorporating this into your program.)
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.
I learnt about the below piece of code, which is claimed to prevent Method Swizzling to some extent.
#ifndef DEBUG
SEC_IS_BEING_DEBUGGED_RETURN_NIL();
#endif
But while including in my project for testing, I get an error.
Implicit declaration of function 'SEC_IS_BEING_DEBUGGED_RETURN_NIL' is
invalid in C99
Can someone help me out on this error, if I need to include any library header for the same.
I didn't intend to answer my own question. From the comment above, I did a search for any such implementation. And Found this In a GitHub Project. Which is a category of NSObject
Perhaps, it would help anyone in future.
#define SEC_IS_BEING_DEBUGGED_RETURN_NIL() size_t size = sizeof(struct kinfo_proc); \
struct kinfo_proc info; \
int ret, name[4]; \
memset(&info, 0, sizeof(struct kinfo_proc)); \
name[0] = CTL_KERN; \
name[1] = KERN_PROC; \
name[2] = KERN_PROC_PID; \
name[3] = getpid(); \
if ((ret = (sysctl(name, 4, &info, &size, NULL, 0)))) { \
if (ret) return nil; \
} \
if (info.kp_proc.p_flag & P_TRACED) return nil
Credits to maker of this
// Created by Derek Selander on a happy day. //
// Copyright (c)
// 2013 Derek Selander. All rights reserved. //
I wrote macro that defines log level and prints out TAG + method name:
#define NSLogDebug(topic, frmt, ...) \
do{ if(LOG_LEVEL >= 4) \
NSLog( (topic #" : " #"%#" #" : " frmt), \
NSStringFromSelector(_cmd), ##__VA_ARGS__); } while(0)
Usage:
#define TAG #"agent_magr"
/* ... */
-(void)registerforDeviceLockNotif
{
NSLogDebug(TAG, #"init");
The output is:
Agent[741:907] agent_magr : registerforDeviceLockNotif : init
However it works only for non-static methods.
Into the method like:
static void displayStatusChanged(/* */)
{}
I get error:
Use of undeclared identifier '_cmd' Did you mean 'rcmd'?
I thought to use __PRETTY_FUNCTION__:
#define NSLogDebug(topic, frmt, ...) \
do{ if(LOG_LEVEL >= 4) \
NSLog( (topic #" : " #"%s" #" : " frmt), \
__PRETTY_FUNCTION__ , ##__VA_ARGS__); } while(0)
but this one prints out full function with parameters:
Agent[773:907] agent_magr : void displayStatusChanged(CFNotificationCenterRef, void *, CFStringRef, const void *, CFDictionaryRef) : init
How can I make it work in static method?
Thanks,
That isn't a static method; it's a function. The _cmd variable only exists in methods (since only methods are called by selectors). If you want this to work in both functions and methods, you'll have to use either __FUNCTION__ or __PRETTY_FUNCTION__, which are both C strings.
You'll want to solve this the same way NSAssert does. Namely, there's a NSCAssert that avoids using _cmd or self. Then you'll use NSLogDebug in Objective-C functions, and NSCLogDebug in C functions. I'd also advising not using the NS namespace here; you'll confuse yourself (or someone else reading the code) later.
Look in NSException.h:
#if !defined(_NSAssertBody)
#define NSAssert(condition, desc, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while(0)
#endif
#if !defined(_NSCAssertBody)
#define NSCAssert(condition, desc, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while(0)
#endif