Files
netio1/make.vsh
T
2026-05-01 23:03:05 +03:00

96 lines
2.5 KiB
V
Executable File

#!/usr/bin/env v
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}) // ${k.to_upper_ascii()}")
}
}
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)!
}