From 5463ea4a2017d4ceb3cc22fee2bdac4cd5c3f508 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Tue, 25 Jul 2023 03:35:05 +0100 Subject: [PATCH] Temporarily disable code that does not compile on windows (#2386) And return ENOSYS. We do that so we can at least compile the code on CI. We'll be gradually enabling more and more functions. Also, enabled `proc_raise()` for windows. --- .github/workflows/compilation_on_windows.yml | 4 +- core/iwasm/common/wasm_runtime_common.c | 9 +- .../sandboxed-system-primitives/src/posix.c | 140 +++++++++++++++++- .../platform/windows/platform_internal.h | 1 + 4 files changed, 149 insertions(+), 5 deletions(-) diff --git a/.github/workflows/compilation_on_windows.yml b/.github/workflows/compilation_on_windows.yml index 0d38e8ae5..416d76099 100644 --- a/.github/workflows/compilation_on_windows.yml +++ b/.github/workflows/compilation_on_windows.yml @@ -60,12 +60,14 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_DEBUG_INTERP=1", "-DWAMR_BUILD_LIB_PTHREAD=1", - "-DWAMR_BUILD_LIB_WASI_THREADS=1" + "-DWAMR_BUILD_LIB_WASI_THREADS=1", + "-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1" ] steps: - uses: actions/checkout@v3 - name: clone uvwasi library + if: ${{ !contains(matrix.build_options, '-DWAMR_BUILD_LIBC_UVWASI=0') }} run: | cd core/deps git clone https://github.com/nodejs/uvwasi.git diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 9269cae34..32c652032 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2907,8 +2907,15 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, dir_list[i], errno); goto fail; } - +#ifdef BH_PLATFORM_WINDOWS + if (error_buf) + snprintf( + error_buf, error_buf_size, + "pre-opening directory is not supported on windows platforms"); + goto fail; +#else raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0); +#endif if (raw_fd == -1) { if (error_buf) snprintf(error_buf, error_buf_size, diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index cf8c12581..66869355c 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -216,6 +216,7 @@ convert_timespec(const struct timespec *ts) } // Converts a CloudABI clock identifier to a POSIX clock identifier. +#ifndef BH_PLATFORM_WINDOWS static bool convert_clockid(__wasi_clockid_t in, clockid_t *out) { @@ -240,6 +241,7 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out) return false; } } +#endif static void wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr, @@ -321,6 +323,9 @@ __wasi_errno_t wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else clockid_t nclock_id; if (!convert_clockid(clock_id, &nclock_id)) return __WASI_EINVAL; @@ -329,6 +334,7 @@ wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, return convert_errno(errno); *resolution = convert_timespec(&ts); return 0; +#endif } __wasi_errno_t @@ -336,6 +342,9 @@ wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, __wasi_timestamp_t *time) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else clockid_t nclock_id; if (!convert_clockid(clock_id, &nclock_id)) return __WASI_EINVAL; @@ -344,6 +353,7 @@ wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id, return convert_errno(errno); *time = convert_timespec(&ts); return 0; +#endif } struct fd_prestat { @@ -443,8 +453,10 @@ struct fd_object { union { // Data associated with directory file descriptors. struct { - struct mutex lock; // Lock to protect members below. - DIR *handle; // Directory handle. + struct mutex lock; // Lock to protect members below. +#ifndef BH_PLATFORM_WINDOWS + DIR *handle; // Directory handle. +#endif __wasi_dircookie_t offset; // Offset of the directory. } directory; }; @@ -579,6 +591,9 @@ fd_determine_type_rights(int fd, __wasi_filetype_t *type, __wasi_rights_t *rights_base, __wasi_rights_t *rights_inheriting) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct stat sb; if (fstat(fd, &sb) < 0) return convert_errno(errno); @@ -648,6 +663,7 @@ fd_determine_type_rights(int fd, __wasi_filetype_t *type, break; } return 0; +#endif } // Returns the underlying file descriptor number of a file descriptor @@ -672,6 +688,9 @@ fd_number(const struct fd_object *fo) static void fd_object_release(struct fd_object *fo) UNLOCKS(fo->refcount) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else if (refcount_release(&fo->refcount)) { switch (fo->type) { case __WASI_FILETYPE_DIRECTORY: @@ -691,6 +710,7 @@ fd_object_release(struct fd_object *fo) UNLOCKS(fo->refcount) } wasm_runtime_free(fo); } +#endif } // Inserts an already existing file descriptor into the file descriptor @@ -698,6 +718,9 @@ fd_object_release(struct fd_object *fo) UNLOCKS(fo->refcount) bool fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) { +#ifdef BH_PLATFORM_WINDOWS + return false; +#else __wasi_filetype_t type; __wasi_rights_t rights_base, rights_inheriting; struct fd_object *fo; @@ -741,6 +764,7 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) fd_table_attach(ft, in, fo, rights_base, rights_inheriting); rwlock_unlock(&ft->lock); return true; +#endif } // Picks an unused slot from the file descriptor table. @@ -784,6 +808,9 @@ fd_table_insert_fd(struct fd_table *ft, int in, __wasi_filetype_t type, __wasi_rights_t rights_inheriting, __wasi_fd_t *out) REQUIRES_UNLOCKED(ft->lock) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_new(type, &fo); @@ -801,6 +828,7 @@ fd_table_insert_fd(struct fd_table *ft, int in, __wasi_filetype_t type, fo->directory.handle = NULL; } return fd_table_insert(ft, fo, rights_base, rights_inheriting, out); +#endif } __wasi_errno_t @@ -938,6 +966,9 @@ wasmtime_ssp_fd_datasync( #endif __wasi_fd_t fd) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_DATASYNC, 0); @@ -953,6 +984,7 @@ wasmtime_ssp_fd_datasync( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -963,6 +995,9 @@ wasmtime_ssp_fd_pread( __wasi_fd_t fd, const __wasi_iovec_t *iov, size_t iovcnt, __wasi_filesize_t offset, size_t *nread) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else if (iovcnt == 0) return __WASI_EINVAL; @@ -1027,6 +1062,7 @@ wasmtime_ssp_fd_pread( return 0; } #endif +#endif } __wasi_errno_t @@ -1037,6 +1073,9 @@ wasmtime_ssp_fd_pwrite( __wasi_fd_t fd, const __wasi_ciovec_t *iov, size_t iovcnt, __wasi_filesize_t offset, size_t *nwritten) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else if (iovcnt == 0) return __WASI_EINVAL; @@ -1081,6 +1120,7 @@ wasmtime_ssp_fd_pwrite( return convert_errno(errno); *nwritten = (size_t)len; return 0; +#endif } __wasi_errno_t @@ -1090,6 +1130,9 @@ wasmtime_ssp_fd_read( #endif __wasi_fd_t fd, const __wasi_iovec_t *iov, size_t iovcnt, size_t *nread) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); @@ -1102,6 +1145,7 @@ wasmtime_ssp_fd_read( return convert_errno(errno); *nread = (size_t)len; return 0; +#endif } __wasi_errno_t @@ -1227,6 +1271,9 @@ wasmtime_ssp_fd_fdstat_get( #endif __wasi_fd_t fd, __wasi_fdstat_t *buf) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_table *ft = curfds; rwlock_rdlock(&ft->lock); struct fd_entry *fe; @@ -1270,6 +1317,7 @@ wasmtime_ssp_fd_fdstat_get( if ((ret & O_SYNC) != 0) buf->fs_flags |= __WASI_FDFLAG_SYNC; return 0; +#endif } __wasi_errno_t @@ -1279,6 +1327,9 @@ wasmtime_ssp_fd_fdstat_set_flags( #endif __wasi_fd_t fd, __wasi_fdflags_t fs_flags) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else int noflags = 0; if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) noflags |= O_APPEND; @@ -1310,6 +1361,7 @@ wasmtime_ssp_fd_fdstat_set_flags( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -1344,6 +1396,9 @@ wasmtime_ssp_fd_sync( #endif __wasi_fd_t fd) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_SYNC, 0); @@ -1355,6 +1410,7 @@ wasmtime_ssp_fd_sync( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -1364,6 +1420,9 @@ wasmtime_ssp_fd_write( #endif __wasi_fd_t fd, const __wasi_ciovec_t *iov, size_t iovcnt, size_t *nwritten) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_WRITE, 0); @@ -1398,6 +1457,7 @@ wasmtime_ssp_fd_write( return convert_errno(errno); *nwritten = (size_t)len; return 0; +#endif } __wasi_errno_t @@ -1476,6 +1536,9 @@ wasmtime_ssp_fd_allocate( #endif __wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ALLOCATE, 0); @@ -1499,6 +1562,7 @@ wasmtime_ssp_fd_allocate( if (ret != 0) return convert_errno(ret); return 0; +#endif } // Reads the entire contents of a symbolic link, returning the contents @@ -1567,6 +1631,9 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, bool needs_final_component) TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else char *path = str_nullterminate(upath, upathlen); if (path == NULL) return convert_errno(errno); @@ -1786,6 +1853,7 @@ fail: fd_object_release(fo); return error; #endif +#endif } static __wasi_errno_t @@ -1817,6 +1885,9 @@ wasmtime_ssp_path_create_directory( #endif __wasi_fd_t fd, const char *path, size_t pathlen) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access pa; __wasi_errno_t error = path_get_nofollow(curfds, &pa, fd, path, pathlen, @@ -1829,11 +1900,13 @@ wasmtime_ssp_path_create_directory( if (ret < 0) return convert_errno(errno); return 0; +#endif } static bool validate_path(const char *path, struct fd_prestats *pt) { +#ifndef BH_PLATFORM_WINDOWS size_t i; char path_resolved[PATH_MAX], prestat_dir_resolved[PATH_MAX]; char *path_real, *prestat_dir_real; @@ -1854,7 +1927,7 @@ validate_path(const char *path, struct fd_prestats *pt) return true; } } - +#endif return false; } @@ -1867,6 +1940,9 @@ wasmtime_ssp_path_link( size_t old_path_len, __wasi_fd_t new_fd, const char *new_path, size_t new_path_len) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access old_pa; __wasi_errno_t error = path_get(curfds, &old_pa, old_fd, old_flags, old_path, old_path_len, @@ -1915,6 +1991,7 @@ wasmtime_ssp_path_link( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -1927,6 +2004,9 @@ wasmtime_ssp_path_open( __wasi_rights_t fs_rights_inheriting, __wasi_fdflags_t fs_flags, __wasi_fd_t *fd) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else // Rights that should be installed on the new file descriptor. __wasi_rights_t rights_base = fs_rights_base; __wasi_rights_t rights_inheriting = fs_rights_inheriting; @@ -2055,6 +2135,7 @@ wasmtime_ssp_path_open( return fd_table_insert_fd(curfds, nfd, type, rights_base & max_base, rights_inheriting & max_inheriting, fd); +#endif } // Copies out directory entry metadata or filename, potentially @@ -2079,6 +2160,9 @@ wasmtime_ssp_fd_readdir( __wasi_fd_t fd, void *buf, size_t nbyte, __wasi_dircookie_t cookie, size_t *bufused) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READDIR, 0); @@ -2168,6 +2252,7 @@ wasmtime_ssp_fd_readdir( mutex_unlock(&fo->directory.lock); fd_object_release(fo); return 0; +#endif } __wasi_errno_t @@ -2178,6 +2263,9 @@ wasmtime_ssp_path_readlink( __wasi_fd_t fd, const char *path, size_t pathlen, char *buf, size_t bufsize, size_t *bufused) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access pa; __wasi_errno_t error = path_get_nofollow( curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_READLINK, 0, false); @@ -2194,6 +2282,7 @@ wasmtime_ssp_path_readlink( return convert_errno(errno); *bufused = (size_t)len < bufsize ? (size_t)len : bufsize; return 0; +#endif } __wasi_errno_t @@ -2204,6 +2293,9 @@ wasmtime_ssp_path_rename( __wasi_fd_t old_fd, const char *old_path, size_t old_path_len, __wasi_fd_t new_fd, const char *new_path, size_t new_path_len) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access old_pa; __wasi_errno_t error = path_get_nofollow(curfds, &old_pa, old_fd, old_path, old_path_len, @@ -2226,8 +2318,10 @@ wasmtime_ssp_path_rename( return convert_errno(errno); } return 0; +#endif } +#ifndef BH_PLATFORM_WINDOWS // Converts a POSIX stat structure to a CloudABI filestat structure. static void convert_stat(const struct stat *in, __wasi_filestat_t *out) @@ -2242,6 +2336,7 @@ convert_stat(const struct stat *in, __wasi_filestat_t *out) .st_ctim = convert_timespec(&in->st_ctim), }; } +#endif __wasi_errno_t wasmtime_ssp_fd_filestat_get( @@ -2250,6 +2345,9 @@ wasmtime_ssp_fd_filestat_get( #endif __wasi_fd_t fd, __wasi_filestat_t *buf) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_GET, 0); @@ -2271,6 +2369,7 @@ wasmtime_ssp_fd_filestat_get( if (ret < 0) return convert_errno(errno); return 0; +#endif } static void @@ -2288,6 +2387,7 @@ convert_timestamp(__wasi_timestamp_t in, struct timespec *out) out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX; } +#ifndef BH_PLATFORM_WINDOWS // Converts the provided timestamps and flags to a set of arguments for // futimens() and utimensat(). static void @@ -2315,6 +2415,7 @@ convert_utimens_arguments(__wasi_timestamp_t st_atim, ts[1].tv_nsec = UTIME_OMIT; } } +#endif __wasi_errno_t wasmtime_ssp_fd_filestat_set_size( @@ -2323,6 +2424,9 @@ wasmtime_ssp_fd_filestat_set_size( #endif __wasi_fd_t fd, __wasi_filesize_t st_size) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_SET_SIZE, 0); @@ -2334,6 +2438,7 @@ wasmtime_ssp_fd_filestat_set_size( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -2344,6 +2449,9 @@ wasmtime_ssp_fd_filestat_set_times( __wasi_fd_t fd, __wasi_timestamp_t st_atim, __wasi_timestamp_t st_mtim, __wasi_fstflags_t fstflags) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else if ((fstflags & ~(__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW | __WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) @@ -2364,6 +2472,7 @@ wasmtime_ssp_fd_filestat_set_times( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -2374,6 +2483,9 @@ wasmtime_ssp_path_filestat_get( __wasi_fd_t fd, __wasi_lookupflags_t flags, const char *path, size_t pathlen, __wasi_filestat_t *buf) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access pa; __wasi_errno_t error = path_get(curfds, &pa, fd, flags, path, pathlen, __WASI_RIGHT_PATH_FILESTAT_GET, 0, false); @@ -2404,6 +2516,7 @@ wasmtime_ssp_path_filestat_get( else if (S_ISSOCK(sb.st_mode)) buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; return 0; +#endif } __wasi_errno_t @@ -2415,6 +2528,9 @@ wasmtime_ssp_path_filestat_set_times( size_t pathlen, __wasi_timestamp_t st_atim, __wasi_timestamp_t st_mtim, __wasi_fstflags_t fstflags) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else if (((fstflags & ~(__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW | __WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) @@ -2443,6 +2559,7 @@ wasmtime_ssp_path_filestat_set_times( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -2453,6 +2570,9 @@ wasmtime_ssp_path_symlink( const char *old_path, size_t old_path_len, __wasi_fd_t fd, const char *new_path, size_t new_path_len) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else char *target = str_nullterminate(old_path, old_path_len); if (target == NULL) return convert_errno(errno); @@ -2480,6 +2600,7 @@ wasmtime_ssp_path_symlink( if (ret < 0) return convert_errno(errno); return 0; +#endif } __wasi_errno_t @@ -2489,6 +2610,9 @@ wasmtime_ssp_path_unlink_file( #endif __wasi_fd_t fd, const char *path, size_t pathlen) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access pa; __wasi_errno_t error = path_get_nofollow( curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_UNLINK_FILE, 0, true); @@ -2517,6 +2641,7 @@ wasmtime_ssp_path_unlink_file( return convert_errno(errno); } return 0; +#endif } __wasi_errno_t @@ -2526,6 +2651,9 @@ wasmtime_ssp_path_remove_directory( #endif __wasi_fd_t fd, const char *path, size_t pathlen) { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else struct path_access pa; __wasi_errno_t error = path_get_nofollow(curfds, &pa, fd, path, pathlen, @@ -2546,6 +2674,7 @@ wasmtime_ssp_path_remove_directory( return convert_errno(errno); } return 0; +#endif } __wasi_errno_t @@ -2556,6 +2685,9 @@ wasmtime_ssp_poll_oneoff( const __wasi_subscription_t *in, __wasi_event_t *out, size_t nsubscriptions, size_t *nevents) NO_LOCK_ANALYSIS { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else // Sleeping. if (nsubscriptions == 1 && in[0].u.type == __WASI_EVENTTYPE_CLOCK) { out[0] = (__wasi_event_t){ @@ -2727,6 +2859,7 @@ wasmtime_ssp_poll_oneoff( else { timeout = -1; } + int ret = poll(pfds, nsubscriptions, timeout); __wasi_errno_t error = 0; @@ -2803,6 +2936,7 @@ wasmtime_ssp_poll_oneoff( wasm_runtime_free(fos); wasm_runtime_free(pfds); return error; +#endif } #if 0 diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index d98f44eb0..b147c5e5b 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" {