Skip to content

c-api: Create and instantiate a component model linker #10598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/c-api/include/wasmtime/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
#define WASMTIME_COMPONENT_H

#include <wasmtime/component/component.h>
#include <wasmtime/component/instance.h>
#include <wasmtime/component/linker.h>

#endif // WASMTIME_COMPONENT_H
5 changes: 3 additions & 2 deletions crates/c-api/include/wasmtime/component/component.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#ifndef WASMTIME_COMPONENT_COMPONENT_H
#define WASMTIME_COMPONENT_COMPONENT_H

#ifdef WASMTIME_FEATURE_COMPONENT_MODEL

#include <wasm.h>
#include <wasmtime/conf.h>
#include <wasmtime/error.h>

#ifdef WASMTIME_FEATURE_COMPONENT_MODEL

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
32 changes: 32 additions & 0 deletions crates/c-api/include/wasmtime/component/instance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef WASMTIME_COMPONENT_INSTANCE_H
#define WASMTIME_COMPONENT_INSTANCE_H

#include <wasmtime/conf.h>

#ifdef WASMTIME_FEATURE_COMPONENT_MODEL

#ifdef __cplusplus
extern "C" {
#endif

/// \brief Representation of a instance in Wasmtime.
///
/// Instances are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Instances cannot
/// interoperate between #wasmtime_store_t instances and if the wrong instance
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
typedef struct wasmtime_component_instance {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
} wasmtime_component_instance_t;

#ifdef __cplusplus
} // extern "C"
#endif

#endif // WASMTIME_FEATURE_COMPONENT_MODEL

#endif // WASMTIME_COMPONENT_INSTANCE_H
63 changes: 63 additions & 0 deletions crates/c-api/include/wasmtime/component/linker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef WASMTIME_COMPONENT_LINKER_H
#define WASMTIME_COMPONENT_LINKER_H

#include <wasm.h>
#include <wasmtime/component/component.h>
#include <wasmtime/component/instance.h>
#include <wasmtime/conf.h>
#include <wasmtime/error.h>
#include <wasmtime/store.h>

#ifdef WASMTIME_FEATURE_COMPONENT_MODEL

#ifdef __cplusplus
extern "C" {
#endif

typedef struct wasmtime_component_linker_t wasmtime_component_linker_t;

/**
* \brief Creates a new #wasmtime_component_linker_t for the specified engine.
*
* \param engine the compilation environment and configuration
*
* \return a pointer to the newly created #wasmtime_component_linker_t
*/
WASM_API_EXTERN wasmtime_component_linker_t *
wasmtime_component_linker_new(const wasm_engine_t *engine);

/**
* \brief Instantiates a component instance in a given #wasmtime_context_t
*
* \param linker a #wasmtime_component_linker_t that will help provide host
* functions
* \param context the #wasmtime_context_t in which the instance should be
* created
* \param component the #wasmtime_component_t to instantiate
* \param instance_out on success, the instantiated
* #wasmtime_component_instance_t
*
* \return wasmtime_error_t* on success `NULL` is returned, otherwise an error
* is returned which describes why the build failed.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_component_linker_instantiate(
const wasmtime_component_linker_t *linker, wasmtime_context_t *context,
const wasmtime_component_t *component,
wasmtime_component_instance_t *instance_out);

/**
* \brief Deletes a #wasmtime_component_linker_t created by
* #wasmtime_component_linker_new
*
* \param linker the #wasmtime_component_linker_t to delete
*/
WASM_API_EXTERN void
wasmtime_component_linker_delete(wasmtime_component_linker_t *linker);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // WASMTIME_FEATURE_COMPONENT_MODEL

#endif // WASMTIME_COMPONENT_LINKER_H
11 changes: 4 additions & 7 deletions crates/c-api/src/component/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,10 @@ pub unsafe extern "C" fn wasmtime_component_new(
len: usize,
component_out: &mut *mut wasmtime_component_t,
) -> Option<Box<wasmtime_error_t>> {
let binary = unsafe { crate::slice_from_raw_parts(buf, len) };
crate::handle_result(
Component::from_binary(&engine.engine, binary),
|component| {
*component_out = Box::into_raw(Box::new(wasmtime_component_t { component }));
},
)
let bytes = unsafe { crate::slice_from_raw_parts(buf, len) };
crate::handle_result(Component::new(&engine.engine, bytes), |component| {
*component_out = Box::into_raw(Box::new(wasmtime_component_t { component }));
})
}

#[unsafe(no_mangle)]
Expand Down
36 changes: 36 additions & 0 deletions crates/c-api/src/component/linker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use wasmtime::component::{Instance, Linker};

use crate::{wasm_engine_t, wasmtime_error_t, WasmtimeStoreContextMut, WasmtimeStoreData};

use super::wasmtime_component_t;

#[repr(transparent)]
pub struct wasmtime_component_linker_t {
pub(crate) linker: Linker<WasmtimeStoreData>,
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasmtime_component_linker_new(
engine: &wasm_engine_t,
) -> Box<wasmtime_component_linker_t> {
Box::new(wasmtime_component_linker_t {
linker: Linker::new(&engine.engine),
})
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasmtime_component_linker_instantiate(
linker: &wasmtime_component_linker_t,
context: WasmtimeStoreContextMut<'_>,
component: &wasmtime_component_t,
instance_out: &mut Instance,
) -> Option<Box<wasmtime_error_t>> {
let result = linker.linker.instantiate(context, &component.component);
crate::handle_result(result, |instance| *instance_out = instance)
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasmtime_component_linker_delete(
_linker: Box<wasmtime_component_linker_t>,
) {
}
2 changes: 2 additions & 0 deletions crates/c-api/src/component/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod component;
mod linker;

pub use component::*;
pub use linker::*;
11 changes: 6 additions & 5 deletions crates/c-api/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ FetchContent_MakeAvailable(googletest)

include(GoogleTest)

function(add_capi_test name)
add_executable(test-${name} ${name}.cc)
function(add_capi_test name path)
add_executable(test-${name} ${path})
target_link_libraries(test-${name} PRIVATE wasmtime-cpp gtest_main)
gtest_discover_tests(test-${name})
endfunction()

add_capi_test(simple)
add_capi_test(types)
add_capi_test(func)
add_capi_test(simple simple.cc)
add_capi_test(types types.cc)
add_capi_test(func func.cc)
add_capi_test(component-instantiate component/instantiate.cc)

# Add a custom test where two files include `wasmtime.hh` and are compiled into
# the same executable (basically makes sure any defined functions in the header
Expand Down
42 changes: 42 additions & 0 deletions crates/c-api/tests/component/instantiate.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <gtest/gtest.h>
#include <wasmtime.h>

TEST(component, instantiate) {
static constexpr auto bytes = std::string_view{
R"END(
(component
(core module)
)
)END",
};

const auto engine = wasm_engine_new();
EXPECT_NE(engine, nullptr);

const auto store = wasmtime_store_new(engine, nullptr, nullptr);
EXPECT_NE(store, nullptr);
const auto context = wasmtime_store_context(store);
EXPECT_NE(context, nullptr);

wasmtime_component_t *component = nullptr;

auto error = wasmtime_component_new(
engine, reinterpret_cast<const uint8_t *>(bytes.data()), bytes.size(),
&component);

EXPECT_EQ(error, nullptr);
EXPECT_NE(component, nullptr);

const auto linker = wasmtime_component_linker_new(engine);
EXPECT_NE(linker, nullptr);

wasmtime_component_instance_t instance = {};
error = wasmtime_component_linker_instantiate(linker, context, component,
&instance);
EXPECT_EQ(error, nullptr);

wasmtime_component_linker_delete(linker);

wasmtime_store_delete(store);
wasm_engine_delete(engine);
}