mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-29 04:57:14 +00:00
Compare commits
27 Commits
b79e3fbcf8
...
a77ead5bdc
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a77ead5bdc | ||
![]() |
0e8b57d8a8 | ||
![]() |
88b5f6a535 | ||
![]() |
ac2fe552d5 | ||
![]() |
ea417d7619 | ||
![]() |
bb36a43fa4 | ||
![]() |
44486c86d2 | ||
![]() |
53c54b9062 | ||
![]() |
cb5975e168 | ||
![]() |
e1b0411cff | ||
![]() |
446c52b8c8 | ||
![]() |
76c14489c5 | ||
![]() |
56526e9776 | ||
![]() |
0df05aff1a | ||
![]() |
70af781bde | ||
![]() |
e4ceb6b429 | ||
![]() |
76392b546b | ||
![]() |
ad6ba3d7cf | ||
![]() |
a7d90ebf59 | ||
![]() |
41bbcb7ded | ||
![]() |
5d34365208 | ||
![]() |
161c945cf7 | ||
![]() |
422c8fb8be | ||
![]() |
0dd7fe2070 | ||
![]() |
799cad659c | ||
![]() |
8c262ba005 | ||
![]() |
ca78c6644e |
|
@ -669,6 +669,10 @@ if (WAMR_BUILD_AOT_VALIDATOR EQUAL 1)
|
||||||
message (" AOT validator enabled")
|
message (" AOT validator enabled")
|
||||||
add_definitions (-DWASM_ENABLE_AOT_VALIDATOR=1)
|
add_definitions (-DWASM_ENABLE_AOT_VALIDATOR=1)
|
||||||
endif ()
|
endif ()
|
||||||
|
if (WAMR_BUILD_INSTRUCTION_METERING EQUAL 1)
|
||||||
|
message (" Instruction metering enabled")
|
||||||
|
add_definitions (-DWASM_ENABLE_INSTRUCTION_METERING=1)
|
||||||
|
endif ()
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Show Phase4 Wasm proposals status.
|
# Show Phase4 Wasm proposals status.
|
||||||
|
|
|
@ -716,4 +716,8 @@ unless used elsewhere */
|
||||||
#define WASM_ENABLE_AOT_VALIDATOR 0
|
#define WASM_ENABLE_AOT_VALIDATOR 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WASM_ENABLE_INSTRUCTION_METERING
|
||||||
|
#define WASM_ENABLE_INSTRUCTION_METERING 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* end of _CONFIG_H_ */
|
#endif /* end of _CONFIG_H_ */
|
||||||
|
|
|
@ -898,6 +898,17 @@ aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx)
|
||||||
if (!strncmp(comp_ctx->target_arch, "riscv32", 7)) {
|
if (!strncmp(comp_ctx->target_arch, "riscv32", 7)) {
|
||||||
add_i64_common_intrinsics(comp_ctx);
|
add_i64_common_intrinsics(comp_ctx);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* LLVM 16 and later expands cttz intrinsic to a table lookup,
|
||||||
|
* which involves some relocations. (unless ZBB is available,
|
||||||
|
* in which case the native instructions are preferred over
|
||||||
|
* the table-based lowering.)
|
||||||
|
* https://reviews.llvm.org/D128911
|
||||||
|
*/
|
||||||
|
#if LLVM_VERSION_MAJOR >= 16
|
||||||
|
add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CTZ);
|
||||||
|
add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_CTZ);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (!strncmp(comp_ctx->target_arch, "xtensa", 6)) {
|
else if (!strncmp(comp_ctx->target_arch, "xtensa", 6)) {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -85,6 +85,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
|
||||||
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
|
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
exec_env->instructions_to_execute = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
return exec_env;
|
return exec_env;
|
||||||
|
|
||||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||||
|
|
|
@ -87,6 +87,11 @@ typedef struct WASMExecEnv {
|
||||||
uint8 *bottom;
|
uint8 *bottom;
|
||||||
} wasm_stack;
|
} wasm_stack;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
/* instructions to execute */
|
||||||
|
int instructions_to_execute;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if WASM_ENABLE_FAST_JIT != 0
|
#if WASM_ENABLE_FAST_JIT != 0
|
||||||
/**
|
/**
|
||||||
* Cache for
|
* Cache for
|
||||||
|
|
|
@ -2285,6 +2285,15 @@ wasm_runtime_access_exce_check_guard_page()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
void
|
||||||
|
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
|
||||||
|
int instructions_to_execute)
|
||||||
|
{
|
||||||
|
exec_env->instructions_to_execute = instructions_to_execute;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
WASMFuncType *
|
WASMFuncType *
|
||||||
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
|
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
|
||||||
uint32 module_type)
|
uint32 module_type)
|
||||||
|
|
|
@ -791,9 +791,17 @@ WASM_RUNTIME_API_EXTERN void
|
||||||
wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
|
wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
|
||||||
uint8 *native_stack_boundary);
|
uint8 *native_stack_boundary);
|
||||||
|
|
||||||
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
/* See wasm_export.h for description */
|
/* See wasm_export.h for description */
|
||||||
WASM_RUNTIME_API_EXTERN void
|
WASM_RUNTIME_API_EXTERN void
|
||||||
|
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
|
||||||
|
int instructions_to_execute);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
||||||
|
/* See wasm_export.h for description */
|
||||||
|
WASM_RUNTIME_API_EXTERN
|
||||||
|
void
|
||||||
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
|
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
|
||||||
bool enable);
|
bool enable);
|
||||||
|
|
||||||
|
|
|
@ -4007,8 +4007,12 @@ aot_resolve_object_relocation_group(AOTObjectData *obj_data,
|
||||||
&& (str_starts_with(relocation->symbol_name, ".LCPI")
|
&& (str_starts_with(relocation->symbol_name, ".LCPI")
|
||||||
|| str_starts_with(relocation->symbol_name, ".LJTI")
|
|| str_starts_with(relocation->symbol_name, ".LJTI")
|
||||||
|| str_starts_with(relocation->symbol_name, ".LBB")
|
|| str_starts_with(relocation->symbol_name, ".LBB")
|
||||||
|| str_starts_with(relocation->symbol_name,
|
|| str_starts_with(relocation->symbol_name, ".Lswitch.table.")
|
||||||
".Lswitch.table."))) {
|
#if LLVM_VERSION_MAJOR >= 16
|
||||||
|
/* cf. https://reviews.llvm.org/D123264 */
|
||||||
|
|| str_starts_with(relocation->symbol_name, ".Lpcrel_hi")
|
||||||
|
#endif
|
||||||
|
)) {
|
||||||
/* change relocation->relocation_addend and
|
/* change relocation->relocation_addend and
|
||||||
relocation->symbol_name */
|
relocation->symbol_name */
|
||||||
LLVMSectionIteratorRef contain_section;
|
LLVMSectionIteratorRef contain_section;
|
||||||
|
|
|
@ -1821,6 +1821,20 @@ WASM_RUNTIME_API_EXTERN void
|
||||||
wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
|
wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
|
||||||
uint8_t *native_stack_boundary);
|
uint8_t *native_stack_boundary);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the instruction count limit to the execution environment.
|
||||||
|
* By default the instruction count limit is -1, which means no limit.
|
||||||
|
* However, if the instruction count limit is set to a positive value,
|
||||||
|
* the execution will be terminated when the instruction count reaches
|
||||||
|
* the limit.
|
||||||
|
*
|
||||||
|
* @param exec_env the execution environment
|
||||||
|
* @param instruction_count the instruction count limit
|
||||||
|
*/
|
||||||
|
WASM_RUNTIME_API_EXTERN void
|
||||||
|
wasm_runtime_set_instruction_count_limit(wasm_exec_env_t exec_env,
|
||||||
|
int instruction_count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dump runtime memory consumption, including:
|
* Dump runtime memory consumption, including:
|
||||||
* Exec env memory consumption
|
* Exec env memory consumption
|
||||||
|
|
|
@ -1516,10 +1516,13 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||||
} \
|
} \
|
||||||
os_mutex_unlock(&exec_env->wait_lock); \
|
os_mutex_unlock(&exec_env->wait_lock); \
|
||||||
} \
|
} \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
goto *handle_table[*frame_ip++]; \
|
goto *handle_table[*frame_ip++]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
|
#define HANDLE_OP_END() \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
FETCH_OPCODE_AND_DISPATCH()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
|
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
|
||||||
|
@ -1542,9 +1545,12 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||||
} \
|
} \
|
||||||
os_mutex_unlock(&exec_env->wait_lock); \
|
os_mutex_unlock(&exec_env->wait_lock); \
|
||||||
} \
|
} \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
continue;
|
continue;
|
||||||
#else
|
#else
|
||||||
#define HANDLE_OP_END() continue
|
#define HANDLE_OP_END() \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
continue;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
|
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
|
||||||
|
@ -1562,6 +1568,18 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
#define CHECK_INSTRUCTION_LIMIT() \
|
||||||
|
if (instructions_left == 0) { \
|
||||||
|
wasm_set_exception(module, "instruction limit exceeded"); \
|
||||||
|
goto got_exception; \
|
||||||
|
} \
|
||||||
|
else if (instructions_left > 0) \
|
||||||
|
instructions_left--;
|
||||||
|
#else
|
||||||
|
#define CHECK_INSTRUCTION_LIMIT() (void)0
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
WASMExecEnv *exec_env,
|
WASMExecEnv *exec_env,
|
||||||
|
@ -1605,6 +1623,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
uint32 local_idx, local_offset, global_idx;
|
uint32 local_idx, local_offset, global_idx;
|
||||||
uint8 local_type, *global_addr;
|
uint8 local_type, *global_addr;
|
||||||
uint32 cache_index, type_index, param_cell_num, cell_num;
|
uint32 cache_index, type_index, param_cell_num, cell_num;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
int instructions_left = -1;
|
||||||
|
if (exec_env) {
|
||||||
|
instructions_left = exec_env->instructions_to_execute;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if WASM_ENABLE_EXCE_HANDLING != 0
|
#if WASM_ENABLE_EXCE_HANDLING != 0
|
||||||
int32_t exception_tag_index;
|
int32_t exception_tag_index;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -105,6 +105,19 @@ typedef float64 CellType_F64;
|
||||||
goto unaligned_atomic; \
|
goto unaligned_atomic; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
#define CHECK_INSTRUCTION_LIMIT() \
|
||||||
|
if (instructions_left == 0) { \
|
||||||
|
wasm_set_exception(module, "instruction limit exceeded"); \
|
||||||
|
goto got_exception; \
|
||||||
|
} \
|
||||||
|
else if (instructions_left > 0) \
|
||||||
|
instructions_left--;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define CHECK_INSTRUCTION_LIMIT() (void)0
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline uint32
|
static inline uint32
|
||||||
rotl32(uint32 n, uint32 c)
|
rotl32(uint32 n, uint32 c)
|
||||||
{
|
{
|
||||||
|
@ -1441,6 +1454,7 @@ wasm_interp_dump_op_count()
|
||||||
do { \
|
do { \
|
||||||
const void *p_label_addr = *(void **)frame_ip; \
|
const void *p_label_addr = *(void **)frame_ip; \
|
||||||
frame_ip += sizeof(void *); \
|
frame_ip += sizeof(void *); \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
goto *p_label_addr; \
|
goto *p_label_addr; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
|
@ -1452,6 +1466,7 @@ wasm_interp_dump_op_count()
|
||||||
/* int32 relative offset was emitted in 64-bit target */ \
|
/* int32 relative offset was emitted in 64-bit target */ \
|
||||||
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
|
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
|
||||||
frame_ip += sizeof(int32); \
|
frame_ip += sizeof(int32); \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
goto *p_label_addr; \
|
goto *p_label_addr; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
|
@ -1462,6 +1477,7 @@ wasm_interp_dump_op_count()
|
||||||
/* uint32 label address was emitted in 32-bit target */ \
|
/* uint32 label address was emitted in 32-bit target */ \
|
||||||
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
|
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
|
||||||
frame_ip += sizeof(int32); \
|
frame_ip += sizeof(int32); \
|
||||||
|
CHECK_INSTRUCTION_LIMIT(); \
|
||||||
goto *p_label_addr; \
|
goto *p_label_addr; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -1538,6 +1554,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
uint8 *maddr = NULL;
|
uint8 *maddr = NULL;
|
||||||
uint32 local_idx, local_offset, global_idx;
|
uint32 local_idx, local_offset, global_idx;
|
||||||
uint8 opcode = 0, local_type, *global_addr;
|
uint8 opcode = 0, local_type, *global_addr;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
int instructions_left = -1;
|
||||||
|
if (exec_env) {
|
||||||
|
instructions_left = exec_env->instructions_to_execute;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||||
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
||||||
|
|
|
@ -9197,6 +9197,15 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode,
|
||||||
loader_ctx->preserved_local_offset += 2;
|
loader_ctx->preserved_local_offset += 2;
|
||||||
emit_label(EXT_OP_COPY_STACK_TOP_I64);
|
emit_label(EXT_OP_COPY_STACK_TOP_I64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* overflow */
|
||||||
|
if (preserved_offset > loader_ctx->preserved_local_offset) {
|
||||||
|
set_error_buf_v(error_buf, error_buf_size,
|
||||||
|
"too much local cells 0x%x",
|
||||||
|
loader_ctx->preserved_local_offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
emit_operand(loader_ctx, local_index);
|
emit_operand(loader_ctx, local_index);
|
||||||
emit_operand(loader_ctx, preserved_offset);
|
emit_operand(loader_ctx, preserved_offset);
|
||||||
emit_label(opcode);
|
emit_label(opcode);
|
||||||
|
|
|
@ -4778,6 +4778,11 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode,
|
||||||
loader_ctx->preserved_local_offset += 2;
|
loader_ctx->preserved_local_offset += 2;
|
||||||
emit_label(EXT_OP_COPY_STACK_TOP_I64);
|
emit_label(EXT_OP_COPY_STACK_TOP_I64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* overflow */
|
||||||
|
bh_assert(preserved_offset
|
||||||
|
<= loader_ctx->preserved_local_offset);
|
||||||
|
|
||||||
emit_operand(loader_ctx, local_index);
|
emit_operand(loader_ctx, local_index);
|
||||||
emit_operand(loader_ctx, preserved_offset);
|
emit_operand(loader_ctx, preserved_offset);
|
||||||
emit_label(opcode);
|
emit_label(opcode);
|
||||||
|
|
|
@ -327,6 +327,10 @@ And the wasm app can calls below APIs to allocate/free memory from/to the shared
|
||||||
- **WAMR_BUILD_SHRUNK_MEMORY**=1/0, default to enable if not set
|
- **WAMR_BUILD_SHRUNK_MEMORY**=1/0, default to enable if not set
|
||||||
> Note: When enabled, this feature will reduce memory usage by decreasing the size of the linear memory, particularly when the `memory.grow` opcode is not used and memory usage is somewhat predictable.
|
> Note: When enabled, this feature will reduce memory usage by decreasing the size of the linear memory, particularly when the `memory.grow` opcode is not used and memory usage is somewhat predictable.
|
||||||
|
|
||||||
|
## **Instruction metering**
|
||||||
|
- **WAMR_BUILD_INSTRUCTION_METERING**=1/0, default to disable if not set
|
||||||
|
> Note: Enabling this feature allows limiting the number of instructions a wasm module instance can execute. Use the `wasm_runtime_set_instruction_count_limit(...)` API before calling `wasm_runtime_call_*(...)` APIs to enforce this limit.
|
||||||
|
|
||||||
## **Combination of configurations:**
|
## **Combination of configurations:**
|
||||||
|
|
||||||
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
# WARM API
|
# WAMR API
|
||||||
|
|
||||||
* **Notice**: The python package `wamr.wamrapi.wamr` need python >= `3.10`.
|
* **Notice**: The python package `wamr.wamrapi.wamr` requires a python version >= `3.10`.
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
### Pre-requisites
|
### Pre-requisites
|
||||||
|
#### Install requirements
|
||||||
|
Before proceeding it is necessary to make sure your Python environment is correctly configured. To do ths open a terminal session in this directory and perfom the following:
|
||||||
|
|
||||||
Install requirements,
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -205,12 +205,3 @@ foreach(EX ${EXAMPLES})
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
find_program(VALGRIND
|
|
||||||
valgrind
|
|
||||||
REQUIRED
|
|
||||||
)
|
|
||||||
|
|
||||||
# run `ctest -T memcheck -V --test-dir build`
|
|
||||||
endif()
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user