96 lines
2.5 KiB
V
Executable File
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)!
|
|
}
|