Skip to content

Commit

Permalink
Several tidyings in the C bindings (bytecodealliance#885)
Browse files Browse the repository at this point in the history
* Several tidyings in the C bindings

- Add several comments to the C bindings output

- Move the `#include <stdlib.h>` out of the `.h` file and into the `.c`
  file, since it's for `realloc`/`free` etc. and those are only used in the
  `.c` file.

- Use named structs inside of typedefs, so that the structs have names
  in the generated debug info.

* Fix `<stdlib.h>` for the Go bindings.

* Fix a stray backslash.

* Ensure that <uchar.h> is included in the header file when needed.

* Remove `__used__` attributes.

* Re-add `__weak__`.
  • Loading branch information
sunfishcode authored Mar 7, 2024
1 parent b6c9de7 commit 046ddcb
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 40 deletions.
98 changes: 59 additions & 39 deletions crates/c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use wit_component::StringEncoding;
struct C {
src: Source,
opts: Opts,
includes: Vec<String>,
h_includes: Vec<String>,
c_includes: Vec<String>,
return_pointer_area_size: usize,
return_pointer_area_align: usize,
names: Ns,
Expand Down Expand Up @@ -181,6 +182,7 @@ impl WorldGenerator for C {
if i == 0 {
let name = resolve.name_world_key(name);
uwriteln!(gen.src.h_fns, "\n// Imported Functions from `{name}`");
uwriteln!(gen.src.c_fns, "\n// Imported Functions from `{name}`");
}
gen.import(Some(name), func);
}
Expand All @@ -202,6 +204,7 @@ impl WorldGenerator for C {
for (i, (_name, func)) in funcs.iter().enumerate() {
if i == 0 {
uwriteln!(gen.src.h_fns, "\n// Imported Functions from `{name}`");
uwriteln!(gen.src.c_fns, "\n// Imported Functions from `{name}`");
}
gen.import(None, func);
}
Expand All @@ -224,6 +227,7 @@ impl WorldGenerator for C {
if i == 0 {
let name = resolve.name_world_key(name);
uwriteln!(gen.src.h_fns, "\n// Exported Functions from `{name}`");
uwriteln!(gen.src.c_fns, "\n// Exported Functions from `{name}`");
}
gen.export(func, Some(name));
}
Expand All @@ -246,6 +250,7 @@ impl WorldGenerator for C {
for (i, (_name, func)) in funcs.iter().enumerate() {
if i == 0 {
uwriteln!(gen.src.h_fns, "\n// Exported Functions from `{name}`");
uwriteln!(gen.src.c_fns, "\n// Exported Functions from `{name}`");
}
gen.export(func, None);
}
Expand All @@ -272,8 +277,12 @@ impl WorldGenerator for C {

fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
let linking_symbol = component_type_object::linking_symbol(&self.world);
self.include("<stdlib.h>");
self.c_include("<stdlib.h>");
let snake = self.world.to_snake_case();
uwriteln!(
self.src.c_adapters,
"\n// Ensure that the *_component_type.o object is linked in"
);
uwrite!(
self.src.c_adapters,
"
Expand All @@ -287,11 +296,11 @@ impl WorldGenerator for C {
self.print_intrinsics();

if self.needs_string {
self.include("<string.h>");
self.c_include("<string.h>");
let (strlen, size) = match self.opts.string_encoding {
StringEncoding::UTF8 => (format!("strlen(s)"), 1),
StringEncoding::UTF16 => {
self.include("<uchar.h>");
self.h_include("<uchar.h>");
uwrite!(
self.src.h_helpers,
"
Expand Down Expand Up @@ -375,18 +384,17 @@ impl WorldGenerator for C {
h_str.deindent(1);
uwriteln!(h_str, "\n#endif\n");

self.include("<stdint.h>");
self.include("<stdbool.h>");

for include in self.includes.iter() {
uwriteln!(h_str, "#include <stdint.h>");
uwriteln!(h_str, "#include <stdbool.h>");
for include in self.h_includes.iter() {
uwriteln!(h_str, "#include {include}");
}

let mut c_str = wit_bindgen_core::Source::default();
wit_bindgen_core::generated_preamble(&mut c_str, version);
uwriteln!(c_str, "#include \"{snake}.h\"");
if c_str.len() > 0 {
c_str.push_str("\n");
for include in self.c_includes.iter() {
uwriteln!(c_str, "#include {include}");
}
c_str.push_str(&self.src.c_defs);
c_str.push_str(&self.src.c_fns);
Expand All @@ -395,7 +403,7 @@ impl WorldGenerator for C {
uwriteln!(
h_str,
"
typedef struct {{\n\
typedef struct {snake}_string_t {{\n\
{ty} *ptr;\n\
size_t len;\n\
}} {snake}_string_t;",
Expand Down Expand Up @@ -490,8 +498,12 @@ impl C {
}
}

fn include(&mut self, s: &str) {
self.includes.push(s.to_string());
fn h_include(&mut self, s: &str) {
self.h_includes.push(s.to_string());
}

fn c_include(&mut self, s: &str) {
self.c_includes.push(s.to_string());
}

fn char_type(&self) -> &'static str {
Expand Down Expand Up @@ -825,6 +837,8 @@ impl C {
fn print_intrinsics(&mut self) {
// Note that these intrinsics are declared as `weak` so they can be
// overridden from some other symbol.
self.src.c_fns("\n// Canonical ABI intrinsics");
self.src.c_fns("\n");
self.src.c_fns(
r#"
__attribute__((__weak__, __export_name__("cabi_realloc")))
Expand Down Expand Up @@ -918,16 +932,15 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
self.src.h_defs("typedef struct {\n");
self.start_typedef_struct(id);
for field in record.fields.iter() {
self.docs(&field.docs, SourceType::HDefs);
self.print_ty(SourceType::HDefs, &field.ty);
self.src.h_defs(" ");
self.src.h_defs(&to_c_ident(&field.name));
self.src.h_defs(";\n");
}
self.src.h_defs("} ");
self.print_typedef_target(id);
self.finish_typedef_struct(id);
}

fn type_resource(&mut self, id: TypeId, name: &str, _docs: &Docs) {
Expand Down Expand Up @@ -1097,13 +1110,12 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
self.src.h_defs("typedef struct {\n");
self.start_typedef_struct(id);
for (i, ty) in tuple.types.iter().enumerate() {
self.print_ty(SourceType::HDefs, ty);
uwriteln!(self.src.h_defs, " f{i};");
}
self.src.h_defs("} ");
self.print_typedef_target(id);
self.finish_typedef_struct(id);
}

fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
Expand Down Expand Up @@ -1133,7 +1145,7 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
fn type_variant(&mut self, id: TypeId, name: &str, variant: &Variant, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
self.src.h_defs("typedef struct {\n");
self.start_typedef_struct(id);
self.src.h_defs(int_repr(variant.tag()));
self.src.h_defs(" tag;\n");

Expand All @@ -1154,8 +1166,7 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
}
self.src.h_defs("} val;\n");
}
self.src.h_defs("} ");
self.print_typedef_target(id);
self.finish_typedef_struct(id);

if variant.cases.len() > 0 {
self.src.h_defs("\n");
Expand All @@ -1175,18 +1186,17 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
self.src.h_defs("typedef struct {\n");
self.start_typedef_struct(id);
self.src.h_defs("bool is_some;\n");
self.print_ty(SourceType::HDefs, payload);
self.src.h_defs(" val;\n");
self.src.h_defs("} ");
self.print_typedef_target(id);
self.finish_typedef_struct(id);
}

fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
self.src.h_defs("typedef struct {\n");
self.start_typedef_struct(id);
self.src.h_defs("bool is_err;\n");
if result.ok.is_some() || result.err.is_some() {
self.src.h_defs("union {\n");
Expand All @@ -1200,8 +1210,7 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
}
self.src.h_defs("} val;\n");
}
self.src.h_defs("} ");
self.print_typedef_target(id);
self.finish_typedef_struct(id);
}

fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
Expand Down Expand Up @@ -1246,12 +1255,11 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
self.src.h_defs("typedef struct {\n");
self.start_typedef_struct(id);
self.print_ty(SourceType::HDefs, ty);
self.src.h_defs(" *ptr;\n");
self.src.h_defs("size_t len;\n");
self.src.h_defs("} ");
self.print_typedef_target(id);
self.finish_typedef_struct(id);
}

fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
Expand Down Expand Up @@ -1353,6 +1361,7 @@ impl InterfaceGenerator<'_> {
}

self.src.h_defs("\ntypedef ");
let name = &self.gen.type_names[&ty];
match kind {
TypeDefKind::Type(_)
| TypeDefKind::Flags(_)
Expand All @@ -1373,26 +1382,23 @@ impl InterfaceGenerator<'_> {
}
}
TypeDefKind::Tuple(t) => {
self.src.h_defs("struct {\n");
self.src.h_defs(&format!("struct {name} {{\n"));
for (i, t) in t.types.iter().enumerate() {
let ty = self.gen.type_name(t);
uwriteln!(self.src.h_defs, "{ty} f{i};");
}
self.src.h_defs("}");
}
TypeDefKind::Option(t) => {
self.src.h_defs("struct {\n");
self.src.h_defs(&format!("struct {name} {{\n"));
self.src.h_defs("bool is_some;\n");
let ty = self.gen.type_name(t);
uwriteln!(self.src.h_defs, "{ty} val;");
self.src.h_defs("}");
}
TypeDefKind::Result(r) => {
self.src.h_defs(
"struct {
bool is_err;
",
);
self.src.h_defs(&format!("struct {name} {{\n"));
self.src.h_defs("bool is_err;\n");
let ok_ty = r.ok.as_ref();
let err_ty = r.err.as_ref();
if ok_ty.is_some() || err_ty.is_some() {
Expand All @@ -1410,7 +1416,7 @@ impl InterfaceGenerator<'_> {
self.src.h_defs("}");
}
TypeDefKind::List(t) => {
self.src.h_defs("struct {\n");
self.src.h_defs(&format!("struct {name} {{\n"));
let ty = self.gen.type_name(t);
uwriteln!(self.src.h_defs, "{ty} *ptr;");
self.src.h_defs("size_t len;\n");
Expand Down Expand Up @@ -1672,6 +1678,8 @@ impl InterfaceGenerator<'_> {
fn export(&mut self, func: &Function, interface_name: Option<&WorldKey>) {
let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func);

self.src.c_fns("\n");

let core_module_name = interface_name.map(|s| self.resolve.name_world_key(s));
let export_name = func.core_export_name(core_module_name.as_deref());

Expand Down Expand Up @@ -1879,6 +1887,18 @@ impl InterfaceGenerator<'_> {
self.src.h_defs(";\n");
}

fn start_typedef_struct(&mut self, id: TypeId) {
let name = &self.gen.type_names[&id];
self.src.h_defs("typedef struct ");
self.src.h_defs(&name);
self.src.h_defs(" {\n");
}

fn finish_typedef_struct(&mut self, id: TypeId) {
self.src.h_defs("} ");
self.print_typedef_target(id);
}

fn owner_namespace(&self, id: TypeId) -> String {
owner_namespace(
self.interface,
Expand Down
1 change: 1 addition & 0 deletions crates/go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ impl WorldGenerator for TinyGo {
self.src.push_str("// #include \"");
self.src.push_str(self.world.to_snake_case().as_str());
self.src.push_str(".h\"\n");
self.src.push_str("// #include <stdlib.h>\n");
if self.preamble.len() > 0 {
self.src.append_src(&self.preamble);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/runtime/resource_import_and_export/wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/* #include <limits.h> */
/* #include <math.h> */
/* #include <stdalign.h> */
/* #include <stdlib.h> */
#include <stdlib.h>
#include <string.h>

struct exports_test_resource_import_and_export_test_thing_t {
Expand Down
1 change: 1 addition & 0 deletions tests/runtime/resources/wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <limits.h>
#include <math.h>
#include <resources.h>
#include <stdlib.h>

struct exports_x_t {
int32_t a;
Expand Down
1 change: 1 addition & 0 deletions tests/runtime/variants/wasm.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <assert.h>
#include <variants.h>
#include <stddef.h>

void variants_test_imports() {
{
Expand Down

0 comments on commit 046ddcb

Please sign in to comment.