** not by client code, so an argument can be made for reducing their
** visibility by not including them in any build-time export lists.
**
-** 2022-09-11: it's not yet _proven_ that this approach works in
-** non-Emscripten builds. If not, such builds will need to export
-** those using the --export=... wasm-ld flag (or equivalent). As of
-** this writing we are tied to Emscripten for various reasons
-** and cannot test the library with other build environments.
+** 2025-12-01: for use in non-Emscripten builds, we need a more
+** invasive macro which explicitly names the export:
+** SQLITE_WASM_EXPORT2.
*/
#define SQLITE_WASM_EXPORT __attribute__((used,visibility("default")))
-// See also:
-//__attribute__((export_name("theExportedName"), used, visibility("default")))
+#define SQLITE_WASM_EXPORT_NAMED(X) __attribute__((export_name(#X),used,visibility("default")))
+#define SQLITE_WASM_EXPORT2(RETTYPE,NAME,SIG) SQLITE_WASM_EXPORT_NAMED(NAME) RETTYPE NAME SIG
-#if 0
+#if 1
/** Increase the kvvfs key size limit from 32. */
-#define KVRECORD_KEY_SZ 64
+#define KVRECORD_KEY_SZ 128
#endif
/*
#undef INC__STRINGIFY
#undef SQLITE_C
-#if 0
-/*
-** An EXPERIMENT in implementing a stack-based allocator analog to
-** Emscripten's stackSave(), stackAlloc(), stackRestore().
-** Unfortunately, this cannot work together with Emscripten because
-** Emscripten defines its own native one and we'd stomp on each
-** other's memory. Other than that complication, basic tests show it
-** to work just fine.
-**
-** Another option is to malloc() a chunk of our own and call that our
-** "stack".
-*/
-SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_end(void){
- extern void __heap_base
- /* see https://stackoverflow.com/questions/10038964 */;
- return &__heap_base;
-}
-SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_begin(void){
- extern void __data_end;
- return &__data_end;
-}
-static void * pWasmStackPtr = 0;
-SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_ptr(void){
- if(!pWasmStackPtr) pWasmStackPtr = sqlite3__wasm_stack_end();
- return pWasmStackPtr;
-}
-SQLITE_WASM_EXPORT void sqlite3__wasm_stack_restore(void * p){
- pWasmStackPtr = p;
-}
-SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_alloc(int n){
- if(n<=0) return 0;
- n = (n + 7) & ~7 /* align to 8-byte boundary */;
- unsigned char * const p = (unsigned char *)sqlite3__wasm_stack_ptr();
- unsigned const char * const b = (unsigned const char *)sqlite3__wasm_stack_begin();
- if(b + n >= p || b + n < b/*overflow*/) return 0;
- return pWasmStackPtr = p - n;
-}
-#endif /* stack allocator experiment */
-
/*
** State for the "pseudo-stack" allocator implemented in
** sqlite3__wasm_pstack_xyz(). In order to avoid colliding with
** the memory on success, 0 on error (including a negative n value). n
** is always adjusted to be a multiple of 8 and returned memory is
** always zeroed out before returning (because this keeps the client
-** JS code from having to do so, and most uses of the pstack will
-** call for doing so).
+** JS code from having to do so, and most uses of the pstack call for
+** doing so).
*/
-SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){
+SQLITE_WASM_EXPORT2(void *,sqlite3__wasm_pstack_alloc,(int n)){
if( n<=0 ) return 0;
n = (n + 7) & ~7 /* align to 8-byte boundary */;
if( PStack.pBegin + n > PStack.pPos /*not enough space left*/
** Return the number of bytes left which can be
** sqlite3__wasm_pstack_alloc()'d.
*/
-SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_remaining(void){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_pstack_remaining,(void)){
assert(PStack.pPos >= PStack.pBegin);
assert(PStack.pPos <= PStack.pEnd);
return (int)(PStack.pPos - PStack.pBegin);
** any space which is currently allocated. This value is a
** compile-time constant.
*/
-SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_quota(void){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_pstack_quota,(void)){
return (int)(PStack.pEnd - PStack.pBegin);
}
void (*xFunc)(void*);
};
typedef struct WasmTestStruct WasmTestStruct;
-SQLITE_WASM_EXPORT
-void sqlite3__wasm_test_struct(WasmTestStruct * s){
+SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_struct,(WasmTestStruct * s)){
if(s){
if( 0 ){
/* Do not be alarmed by the small (and odd) pointer values.
** fails to compile with "tables may not be 64-bit" but does not tell
** us where it's happening.
*/
-SQLITE_WASM_EXPORT
-const char * sqlite3__wasm_enum_json(void){
+SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){
static char aBuffer[1024 * 20] =
{0} /* where the JSON goes. 2025-09-19: output size=19295, but
that can vary slightly from build to build, so a little
** method, SQLITE_MISUSE is returned, else the result of the xDelete()
** call is returned.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vfs_unlink,(sqlite3_vfs *pVfs, const char *zName)){
int rc = SQLITE_MISUSE /* ??? */;
if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0);
if( zName && pVfs && pVfs->xDelete ){
** defaulting to "main" if zDbName is 0. Returns 0 if no db with the
** given name is open.
*/
-SQLITE_WASM_EXPORT
-sqlite3_vfs * sqlite3__wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
+SQLITE_WASM_EXPORT2(sqlite3_vfs *,sqlite3__wasm_db_vfs,(sqlite3 *pDb, const char *zDbName)){
sqlite3_vfs * pVfs = 0;
sqlite3_file_control(pDb, zDbName ? zDbName : "main",
SQLITE_FCNTL_VFS_POINTER, &pVfs);
** Returns 0 on success, an SQLITE_xxx code on error. Returns
** SQLITE_MISUSE if pDb is NULL.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_db_reset(sqlite3 *pDb){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_reset,(sqlite3 *pDb)){
int rc = SQLITE_MISUSE;
if( pDb ){
sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0);
** If `*pOut` is not NULL, the caller is responsible for passing it to
** sqlite3_free() to free it.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
- unsigned char **pOut,
- sqlite3_int64 *nOut, unsigned int mFlags ){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_serialize,
+ (sqlite3 *pDb, const char *zSchema,
+ unsigned char **pOut,
+ sqlite3_int64 *nOut, unsigned int mFlags)){
unsigned char * z;
if( !pDb || !pOut ) return SQLITE_MISUSE;
if( nOut ) *nOut = 0;
** portability, so that the API can still work in builds where BigInt
** support is disabled or unavailable.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_vfs_create_file( sqlite3_vfs *pVfs,
- const char *zFilename,
- const unsigned char * pData,
- int nData ){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vfs_create_file,
+ (sqlite3_vfs *pVfs, const char *zFilename,
+ const unsigned char * pData, int nData)){
int rc;
sqlite3_file *pFile = 0;
sqlite3_io_methods const *pIo;
** zFilename, appends pData bytes to it, and returns 0 on success or
** SQLITE_IOERR on error.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_posix_create_file( const char *zFilename,
- const unsigned char * pData,
- int nData ){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_posix_create_file,
+ (const char *zFilename, const unsigned char * pData,
+ int nData)){
int rc;
FILE * pFile = 0;
int fileExisted = 0;
** This returns either a pointer to a static buffer or zKeyIn directly
** (if zClass is NULL or empty).
*/
-SQLITE_WASM_EXPORT
-const char * sqlite3__wasm_kvvfsMakeKey(const char *zClass,
- const char *zKeyIn){
+SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_kvvfsMakeKey,
+ (const char *zClass, const char *zKeyIn)){
static char buf[SQLITE_KVOS_SZ+1] = {0};
assert(sqlite3KvvfsMethods.nKeySize>24);
if( zClass && *zClass ){
** Returns the pointer to the singleton object which holds the kvvfs
** I/O methods and associated state.
*/
-SQLITE_WASM_EXPORT
-sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){
+SQLITE_WASM_EXPORT2(sqlite3_kvvfs_methods *,sqlite3__wasm_kvvfs_methods,(void)){
return &sqlite3KvvfsMethods;
}
** sqlite3_vtab_config(), or SQLITE_MISUSE if the 2nd arg is not a
** valid value.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_vtab_config,
+ (sqlite3 *pDb, int op, int arg)){
switch(op){
case SQLITE_VTAB_DIRECTONLY:
case SQLITE_VTAB_INNOCUOUS:
** Wrapper for the variants of sqlite3_db_config() which take
** (int,int*) variadic args.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_ip,
+ (sqlite3 *pDb, int op, int arg1, int* pArg2)){
switch(op){
case SQLITE_DBCONFIG_ENABLE_FKEY:
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
** Wrapper for the variants of sqlite3_db_config() which take
** (void*,int,int) variadic args.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_pii,
+ (sqlite3 *pDb, int op, void * pArg1, int arg2,
+ int arg3)){
switch(op){
case SQLITE_DBCONFIG_LOOKASIDE:
return sqlite3_db_config(pDb, op, pArg1, arg2, arg3);
** Wrapper for the variants of sqlite3_db_config() which take
** (const char *) variadic args.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_s,(sqlite3 *pDb, int op,
+ const char *zArg)){
switch(op){
case SQLITE_DBCONFIG_MAINDBNAME:
return sqlite3_db_config(pDb, op, zArg);
** Binding for combinations of sqlite3_config() arguments which take
** a single integer argument.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_config_i(int op, int arg){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_i,(int op, int arg)){
return sqlite3_config(op, arg);
}
** Binding for combinations of sqlite3_config() arguments which take
** two int arguments.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_config_ii(int op, int arg1, int arg2){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_ii,(int op, int arg1, int arg2)){
return sqlite3_config(op, arg1, arg2);
}
** Binding for combinations of sqlite3_config() arguments which take
** a single i64 argument.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_config_j(int op, sqlite3_int64 arg){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_config_j,(int op, sqlite3_int64 arg)){
return sqlite3_config(op, arg);
}
** sqlite3_mprintf()'s %Q modifier (if addQuotes is true) or %q (if
** addQuotes is 0). Returns NULL if z is NULL or on OOM.
*/
-SQLITE_WASM_EXPORT
-char * sqlite3__wasm_qfmt_token(char *z, int addQuotes){
+SQLITE_WASM_EXPORT2(char *,sqlite3__wasm_qfmt_token,(char *z, int addQuotes)){
char * rc = 0;
if( z ){
rc = addQuotes
** A WASM wrapper for the interal os_kv.c:kvvfsDecode() for internal
** use by the kvvfs v2 API.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_kvvfs_decode(const char *a, char *aOut, int nOut){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_kvvfs_decode,(const char *a, char *aOut, int nOut)){
return kvvfsDecode(a, aOut, nOut);
}
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_kvvfs_encode(const char *a, int nA, char *aOut){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_kvvfs_encode,(const char *a, int nA, char *aOut)){
return kvvfsEncode(a, nA, aOut);
}
** the virtual FS fails. In builds compiled without SQLITE_ENABLE_WASMFS
** defined, SQLITE_NOTFOUND is returned without side effects.
*/
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_init_wasmfs(const char *zMountPoint){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_init_wasmfs,(const char *zMountPoint)){
static backend_t pOpfs = 0;
if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
if( !pOpfs ){
return pOpfs ? 0 : SQLITE_NOMEM;
}
#else
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_init_wasmfs(const char *zUnused){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_init_wasmfs,(const char *zUnused)){
//emscripten_console_warn("WASMFS OPFS is not compiled in.");
(void)zUnused;
return SQLITE_NOTFOUND;
#if SQLITE_WASM_ENABLE_C_TESTS
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_test_intptr(int * p){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_test_intptr,(int * p)){
return *p = *p * 2;
}
-SQLITE_WASM_EXPORT
-void * sqlite3__wasm_test_voidptr(void * p){
+SQLITE_WASM_EXPORT2(void *,sqlite3__wasm_test_voidptr,(void * p)){
return p;
}
-SQLITE_WASM_EXPORT
-int64_t sqlite3__wasm_test_int64_max(void){
+SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64_max,(void)){
return (int64_t)0x7fffffffffffffff;
}
-SQLITE_WASM_EXPORT
-int64_t sqlite3__wasm_test_int64_min(void){
+SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64_min,(void)){
return ~sqlite3__wasm_test_int64_max();
}
-SQLITE_WASM_EXPORT
-int64_t sqlite3__wasm_test_int64_times2(int64_t x){
+SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64_times2,(int64_t x)){
return x * 2;
}
-SQLITE_WASM_EXPORT
-void sqlite3__wasm_test_int64_minmax(int64_t * min, int64_t *max){
+SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_int64_minmax,(int64_t * min, int64_t *max)){
*max = sqlite3__wasm_test_int64_max();
*min = sqlite3__wasm_test_int64_min();
/*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
}
-SQLITE_WASM_EXPORT
-int64_t sqlite3__wasm_test_int64ptr(int64_t * p){
+SQLITE_WASM_EXPORT2(int64_t,sqlite3__wasm_test_int64ptr,(int64_t * p)){
/*printf("sqlite3__wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
return *p = *p * 2;
}
-SQLITE_WASM_EXPORT
-void sqlite3__wasm_test_stack_overflow(int recurse){
+SQLITE_WASM_EXPORT2(void,sqlite3__wasm_test_stack_overflow,(int recurse)){
if(recurse) sqlite3__wasm_test_stack_overflow(recurse);
}
/* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */
-SQLITE_WASM_EXPORT
-char * sqlite3__wasm_test_str_hello(int fail){
+SQLITE_WASM_EXPORT2(char *,sqlite3__wasm_test_str_hello,(int fail)){
char * s = fail ? 0 : (char *)sqlite3_malloc(6);
if(s){
memcpy(s, "hello", 5);
return *z==0;
}
-SQLITE_WASM_EXPORT
-int sqlite3__wasm_SQLTester_strglob(const char *zGlob, const char *z){
+SQLITE_WASM_EXPORT2(int,sqlite3__wasm_SQLTester_strglob,
+ (const char *zGlob, const char *z)){
return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z);
}