upd6
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env -S v run
|
||||
|
||||
import os
|
||||
import rand
|
||||
import strings
|
||||
|
||||
/*
|
||||
This is a C bindings generator for netio module.
|
||||
|
||||
This script uses the C preprocessor (`cc`) to extract macros using programs
|
||||
from `cincludes` and generates a V module file with constants.
|
||||
|
||||
The C defines (`#define`) are parsed and used to generate a temporary
|
||||
V program (`vprogram`), which generates the final V module file.
|
||||
|
||||
The goal is for the final V module file to contain only the values of C
|
||||
constants, rather than calling C code directly.
|
||||
*/
|
||||
|
||||
const cincludes = {
|
||||
'Linux': '
|
||||
|#include <netinet/in.h>
|
||||
|#include <sys/socket.h>
|
||||
|#include <netdb.h>'
|
||||
'FreeBSD': '
|
||||
|#include <netinet/in.h>
|
||||
|#include <sys/socket.h>
|
||||
|#include <netdb.h>'
|
||||
}
|
||||
|
||||
const typemap = {
|
||||
'SocketType': ['SOCK_']
|
||||
'SocketLevel': ['SOL_', 'IPPROTO_']
|
||||
'SocketOption': ['SO_', 'IP_', 'IPV6_']
|
||||
'AddrFamily': ['AF_']
|
||||
'AddrInfoFlag': ['AI_']
|
||||
'NameInfoFlag': ['NI_']
|
||||
'MsgFlag': ['MSG_']
|
||||
}
|
||||
|
||||
const vprogram = r'module main
|
||||
|
||||
%includes
|
||||
|
||||
fn main() {
|
||||
// Generate the final .v file
|
||||
println("module netio\n")
|
||||
println("/*")
|
||||
println("\tThis file is generated by make.vsh, DO NOT EDIT.")
|
||||
println("*/\n")
|
||||
for k, v in cdefs {
|
||||
println("pub const ${k} = ${v.vtype}(${v.value})")
|
||||
}
|
||||
}
|
||||
|
||||
struct CDef {
|
||||
vtype string
|
||||
value isize
|
||||
}
|
||||
'
|
||||
|
||||
const cc = 'cc'
|
||||
const cflags = os.getenv('CFLAGS')
|
||||
|
||||
fn main() {
|
||||
cprogram :=
|
||||
cincludes[os.uname().sysname] or { panic('platform is not yet supported') }.strip_margin().trim_space()
|
||||
cc_cmd := "echo '${cprogram}' | ${cc} -x c - -E -dM ${cflags} | sort -k 2 -V"
|
||||
cc_out := os.execute_or_panic(cc_cmd)
|
||||
mut buf := strings.new_builder(1024)
|
||||
buf.writeln(vprogram.replace('%includes', cprogram))
|
||||
buf.writeln('const cdefs = {')
|
||||
for line in cc_out.output.split_into_lines() {
|
||||
for vtype, cdef_prefixes in typemap {
|
||||
for cdef_prefix in cdef_prefixes {
|
||||
if line.starts_with('#define ${cdef_prefix}') {
|
||||
cconst_name := line.fields()[1]
|
||||
if cconst_name.contains('(') {
|
||||
continue // skip non-constant macros
|
||||
}
|
||||
buf.writeln("'${cconst_name.to_lower_ascii()}': CDef{'${vtype}', C.${cconst_name}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.write_byte(`}`)
|
||||
vfile_path := os.join_path_single(os.temp_dir(), rand.string(10) + '.c.v')
|
||||
os.write_file(vfile_path, buf.str())!
|
||||
os.execute_or_panic('v -Wfatal-errors -W -N ${vfile_path}')
|
||||
os.execute_or_panic('v fmt -w ${vfile_path}')
|
||||
v_out := os.execute_or_panic('${vfile_path.replace('.c.v', '')}')
|
||||
print(v_out.output)
|
||||
flush_stdout()
|
||||
os.rm(vfile_path)!
|
||||
}
|
||||
Reference in New Issue
Block a user