Skip to content

Commit

Permalink
feat(WASI): Support itk_wasm_delayed_start
Browse files Browse the repository at this point in the history
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
  • Loading branch information
thewtex committed Oct 5, 2022
1 parent 3efaf52 commit a4609a6
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 6 deletions.
10 changes: 6 additions & 4 deletions src/docker/itk-wasm/ITKWebAssemblyInterface.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,17 @@ function(add_executable target)
set_property(TARGET ${wasm_target} PROPERTY LINK_FLAGS_DEBUG " -fno-lto -s SAFE_HEAP=1 -s DISABLE_EXCEPTION_CATCHING=0 --bind ${_link_flags_debug}")
set_property(TARGET ${umd_target} PROPERTY LINK_FLAGS_DEBUG " -fno-lto -s SAFE_HEAP=1 -s DISABLE_EXCEPTION_CATCHING=0 --bind ${_link_flags_debug}")
else()
# WASI
set_property(TARGET ${wasm_target} PROPERTY SUFFIX ".wasi.wasm")
if (NOT TARGET wasi-exception-shim AND DEFINED CMAKE_CXX_COMPILE_OBJECT)
add_library(wasi-exception-shim STATIC /ITKWebAssemblyInterface/src/exceptionShim.cxx)
if (NOT TARGET wasi-itk-extras AND DEFINED CMAKE_CXX_COMPILE_OBJECT)
add_library(wasi-itk-extras STATIC /ITKWebAssemblyInterface/src/exceptionShim.cxx /ITKWebAssemblyInterface/src/initialization.cxx)
endif()
get_property(_is_imported TARGET ${wasm_target} PROPERTY IMPORTED)
if (NOT ${_is_imported})
_target_link_libraries(${target} PRIVATE $<$<LINK_LANGUAGE:CXX>:wasi-exception-shim>)
_target_link_libraries(${target} PRIVATE $<$<LINK_LANGUAGE:CXX>:wasi-itk-extras>)
get_property(_link_flags TARGET ${wasm_target} PROPERTY LINK_FLAGS)
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}")
set_property(TARGET ${wasm_target} PROPERTY LINK_FLAGS
"-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}")
if(NOT ITK_WASM_NO_INTERFACE_LINK)
if(NOT TARGET WebAssemblyInterface)
find_package(ITK QUIET COMPONENTS WebAssemblyInterface)
Expand Down
69 changes: 69 additions & 0 deletions src/initialization.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*=========================================================================
*
* Copyright NumFOCUS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
// itk-wasm reactor-like initialization to lower values before _start
// Based on wasi-libc.


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

#include <wasi/api.h>
extern void __wasm_call_ctors(void);
extern int __main_void(void);
extern void __wasm_call_dtors(void);
extern void _initialize(void);

__attribute__((export_name("itk_wasm_delayed_exit")))
void itk_wasm_delayed_exit(int returnCode)
{
// Call atexit functions, destructors, stdio cleanup, etc.
__wasm_call_dtors();

// If main exited successfully, just return, otherwise call
// `__wasi_proc_exit`.
if (returnCode != 0) {
__wasi_proc_exit(returnCode);
}
}

__attribute__((export_name("itk_wasm_delayed_start")))
int itk_wasm_delayed_start(void)
{
// Call `__main_void` which will either be the application's zero-argument
// `__main_void` function or a libc routine which obtains the command-line
// arguments and calls `__main_argv_argc`.
const int r = __main_void();

return r;
}

__attribute__((export_name("")))
void _start(void)
{
_initialize();

const int returnCode = itk_wasm_delayed_start();

itk_wasm_delayed_exit(returnCode);
}


#ifdef __cplusplus
}
#endif // __cplusplus
10 changes: 8 additions & 2 deletions src/python/itkwasm/itkwasm/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,11 @@ def run(self, args: List[str], outputs=[], inputs=[], preopen_directories=[], ma

instance = Instance(self.module, import_object)

start = instance.exports._start
start()
_initialize = instance.exports._initialize
_initialize()

delayed_start = instance.exports.itk_wasm_delayed_start
return_code = delayed_start()

delayed_exit = instance.exports.itk_wasm_delayed_exit
delayed_exit(return_code)
Binary file modified src/python/itkwasm/test/input/stdout-stderr-test.wasi.wasm
Binary file not shown.

0 comments on commit a4609a6

Please sign in to comment.