Skip to content

Commit a4609a6

Browse files
committed
feat(WASI): Support itk_wasm_delayed_start
Build as a Reactor but add a default export, defined by the empty string, that behaves like _start did before for command line execution via wasmtime. https://docs.rs/wasmtime/0.17.0/src/wasmtime/linker.rs.html#685
1 parent 3efaf52 commit a4609a6

File tree

4 files changed

+83
-6
lines changed

4 files changed

+83
-6
lines changed

src/docker/itk-wasm/ITKWebAssemblyInterface.cmake

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,17 @@ function(add_executable target)
5555
set_property(TARGET ${wasm_target} PROPERTY LINK_FLAGS_DEBUG " -fno-lto -s SAFE_HEAP=1 -s DISABLE_EXCEPTION_CATCHING=0 --bind ${_link_flags_debug}")
5656
set_property(TARGET ${umd_target} PROPERTY LINK_FLAGS_DEBUG " -fno-lto -s SAFE_HEAP=1 -s DISABLE_EXCEPTION_CATCHING=0 --bind ${_link_flags_debug}")
5757
else()
58+
# WASI
5859
set_property(TARGET ${wasm_target} PROPERTY SUFFIX ".wasi.wasm")
59-
if (NOT TARGET wasi-exception-shim AND DEFINED CMAKE_CXX_COMPILE_OBJECT)
60-
add_library(wasi-exception-shim STATIC /ITKWebAssemblyInterface/src/exceptionShim.cxx)
60+
if (NOT TARGET wasi-itk-extras AND DEFINED CMAKE_CXX_COMPILE_OBJECT)
61+
add_library(wasi-itk-extras STATIC /ITKWebAssemblyInterface/src/exceptionShim.cxx /ITKWebAssemblyInterface/src/initialization.cxx)
6162
endif()
6263
get_property(_is_imported TARGET ${wasm_target} PROPERTY IMPORTED)
6364
if (NOT ${_is_imported})
64-
_target_link_libraries(${target} PRIVATE $<$<LINK_LANGUAGE:CXX>:wasi-exception-shim>)
65+
_target_link_libraries(${target} PRIVATE $<$<LINK_LANGUAGE:CXX>:wasi-itk-extras>)
6566
get_property(_link_flags TARGET ${wasm_target} PROPERTY LINK_FLAGS)
66-
set_property(TARGET ${wasm_target} PROPERTY LINK_FLAGS "-Wl,--export-if-defined=main -Wl,--export-if-defined=itk_wasm_input_array_alloc -Wl,--export-if-defined=itk_wasm_input_json_alloc -Wl,--export-if-defined=itk_wasm_output_json_address -Wl,--export-if-defined=itk_wasm_output_json_size -Wl,--export-if-defined=itk_wasm_output_array_address -Wl,--export-if-defined=itk_wasm_output_array_size -Wl,--export-if-defined=itk_wasm_free_all ${_link_flags}")
67+
set_property(TARGET ${wasm_target} PROPERTY LINK_FLAGS
68+
"-mexec-model=reactor -Wl,--export-if-defined=itk_wasm_input_array_alloc -Wl,--export-if-defined=itk_wasm_input_json_alloc -Wl,--export-if-defined=itk_wasm_output_json_address -Wl,--export-if-defined=itk_wasm_output_json_size -Wl,--export-if-defined=itk_wasm_output_array_address -Wl,--export-if-defined=itk_wasm_output_array_size -Wl,--export-if-defined=itk_wasm_free_all -Wl,--export-if-defined=_start -Wl,--export-if-defined=itk_wasm_delayed_start -Wl,--export-if-defined=itk_wasm_delayed_exit ${_link_flags}")
6769
if(NOT ITK_WASM_NO_INTERFACE_LINK)
6870
if(NOT TARGET WebAssemblyInterface)
6971
find_package(ITK QUIET COMPONENTS WebAssemblyInterface)

src/initialization.cxx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*=========================================================================
2+
*
3+
* Copyright NumFOCUS
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
// itk-wasm reactor-like initialization to lower values before _start
19+
// Based on wasi-libc.
20+
21+
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif // __cplusplus
25+
26+
#include <wasi/api.h>
27+
extern void __wasm_call_ctors(void);
28+
extern int __main_void(void);
29+
extern void __wasm_call_dtors(void);
30+
extern void _initialize(void);
31+
32+
__attribute__((export_name("itk_wasm_delayed_exit")))
33+
void itk_wasm_delayed_exit(int returnCode)
34+
{
35+
// Call atexit functions, destructors, stdio cleanup, etc.
36+
__wasm_call_dtors();
37+
38+
// If main exited successfully, just return, otherwise call
39+
// `__wasi_proc_exit`.
40+
if (returnCode != 0) {
41+
__wasi_proc_exit(returnCode);
42+
}
43+
}
44+
45+
__attribute__((export_name("itk_wasm_delayed_start")))
46+
int itk_wasm_delayed_start(void)
47+
{
48+
// Call `__main_void` which will either be the application's zero-argument
49+
// `__main_void` function or a libc routine which obtains the command-line
50+
// arguments and calls `__main_argv_argc`.
51+
const int r = __main_void();
52+
53+
return r;
54+
}
55+
56+
__attribute__((export_name("")))
57+
void _start(void)
58+
{
59+
_initialize();
60+
61+
const int returnCode = itk_wasm_delayed_start();
62+
63+
itk_wasm_delayed_exit(returnCode);
64+
}
65+
66+
67+
#ifdef __cplusplus
68+
}
69+
#endif // __cplusplus

src/python/itkwasm/itkwasm/pipeline.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,11 @@ def run(self, args: List[str], outputs=[], inputs=[], preopen_directories=[], ma
3333

3434
instance = Instance(self.module, import_object)
3535

36-
start = instance.exports._start
37-
start()
36+
_initialize = instance.exports._initialize
37+
_initialize()
38+
39+
delayed_start = instance.exports.itk_wasm_delayed_start
40+
return_code = delayed_start()
41+
42+
delayed_exit = instance.exports.itk_wasm_delayed_exit
43+
delayed_exit(return_code)
Binary file not shown.

0 commit comments

Comments
 (0)