SQLite User Forum

Most extensions break SQLite library when using EXTRA_SRC
Login

Most extensions break SQLite library when using EXTRA_SRC

(1) By anonymous on 2024-12-06 15:27:40 [source]

Most (if not all) of the extensions in ext/misc produce an unusable library when included with EXTRA_SRC - but only on Windows.

What happens is that there is no test for SQLITE_AMALGAMATION leading to 'sqlite3ext.h' being included unconditionally.

Then __declspec(dllexport) is processed resulting in all previously generated exports being lost and only the init code for the extension remaining.

The library is then unusable with the entire API missing.

(2) By Stephan Beal (stephan) on 2024-12-06 15:45:11 in reply to 1 [link] [source]

Most (if not all) of the extensions in ext/misc produce an unusable library when included with EXTRA_SRC - but only on Windows.

Please show us precisely what you're doing and tell us which source version you're using. If it's from the trunk, it's quite possible that that capability was overlooked or not yet ported over from the legacy build.

(3) By anonymous on 2024-12-06 22:28:58 in reply to 2 [link] [source]

The versions are 3.46.1, 3.47.1 and trunk (3b82d2c6b7)

First the library and amalgamation are built on Linux:

configure --disable-tcl make libsqlite3.la "CFLAGS= -O2 -DSQLITE_CUSTOM_INCLUDE=options.h" EXTRA_SRC="ext/misc/eval.c" [1] make libsqlite3.so "CFLAGS= -O2 -DSQLITE_CUSTOM_INCLUDE=options.h" EXTRA_SRC="ext/misc/eval.c" [2]

[1] = 3.46.1 & 3.47.1

[2] = trunk

Then the library is built on Windows:

GCC -Wall -O2 -m32 -DSQLITE_CUSTOM_INCLUDE=options.h -I. -c .\sqlite3.c -o .\sqlite3.o G++ -m32 -luser32 -shared -Wl,--output-def=sqlite3.def -Wl,--out-implib=sqlite3.a -Wl,--dll sqlite3.o -o sqlite3.dll -s

Build appears ok, but produces a sqlite3.def with only the init code for eval.

I found this related post.

Changing some code in eval.c does the trick:

/* fix for using EXTRA_SRC (1) */ #ifndef SQLITE_AMALGAMATION #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <string.h> #endif

And:

/* fix for using EXTRA_SRC (2) */ #ifndef SQLITE_AMALGAMATION #ifdef _WIN32 __declspec(dllexport) #endif #endif

And:

/* fix for using EXTRA_SRC (3) */ #ifndef SQLITE_AMALGAMATION SQLITE_EXTENSION_INIT2(pApi); #endif

That results in a working library on Windows.

(4) By Stephan Beal (stephan) on 2024-12-06 22:51:34 in reply to 3 [link] [source]

Changing some code in eval.c does the trick:

 #ifndef SQLITE_AMALGAMATION

Looking over a handful of other extensions, such as shathree.c, sha1.c, and decimal.c, they all follow precisely the same pattern as eval.c does. What happens differently, though, when they're copied into the generated shell.c, is that the __declspec(dllexport) part is stripped out by the script which generates shell.c:

#ifdef _WIN32

#endif
int sqlite3_sha_init(...)

(The blank line there holds the declspec part in the original copy of that file.)

Presumably removing only that one piece from eval.c will also produce a working bundle for you:

#ifdef _WIN32
__declspec(dllexport) /* Try removing only this line. */
#endif
int sqlite3_eval_init(...){...}

That said: i've no way of testing Windows-specific changes so can't try this myself.

(5) By anonymous on 2024-12-06 23:29:31 in reply to 4 [link] [source]

Yes, they do. And I modified all other extensions I use in exactly the same way.

Ah... I didn't check out the generated code for shell.c. So a SED or AWK oneliner should work (never used TCL).

Yes, removing __declspec(dllexport) works, but the test for SQLITE_AMALGAMATION feels cleaner.

Removing sqlite3ext.h should not be necessary, but it caused some issue in one extension - I don't remember which and what but I then changed every extension I include.

Now there is only the question if and what could/should be changed: the source of all extensions, the generation of the amalgamation or a warning in the documentation. Someday someone will trip over the same issue.

(6) By Stephan Beal (stephan) on 2024-12-06 23:37:16 in reply to 5 [link] [source]

Yes, removing __declspec(dllexport) works, but the test for SQLITE_AMALGAMATION feels cleaner.

We have a build of shell.c which does not use the amalgamation, and my untested suspicion is that approach would break that build. (Declspec is a Windows-ism, so i'm unable to test that hypothesis.)

Now there is only the question if and what could/should be changed: the source of all extensions, the generation of the amalgamation or a warning in the documentation.

That's precisely what i'm just asking myself ;) and will bring it up with the other devs.

The hypothetical warning in the docs would be what, that any declspec lines need to be removed?

(7) By anonymous on 2024-12-07 16:17:42 in reply to 6 [link] [source]

We have a build of shell.c which does not use the amalgamation, and my untested suspicion is that approach would break that build.

If the build process generates a monolithic source that is then compiled into an executable a stray declspec should not break anything.

If however source files are compiled separately and then linked together any stray declspec could (and probably would) break this build on Windows.

You could introduce another switch for that build. I'm not to keen on that - eventually you would end up with sources so littered with switches that they become unreadable.

In this case I would stick with having TCL stripping any unwanted declspec.

(8) By anonymous on 2024-12-07 16:28:12 in reply to 6 [link] [source]

The hypothetical warning in the docs would be what, that any declspec lines need to be removed?

Yes.

The warning should be that if you add any source files using EXTRA_SRC these should never contain a declspec.

Considering the target audience (people that are able and willing to add their own extensions) that should be enough. And they could then pick their solution: manually deleting them or putting them behind SQLITE_AMALGAMATION (or another switch).

(9) By Stephan Beal (stephan) on 2024-12-08 18:59:13 in reply to 8 [link] [source]

The warning should be that if you add any source files using EXTRA_SRC these should never contain a declspec.

A note warning about the possible need to edit those files, with a link back to this forum thread, has been added to the Windows-specific makefile in the trunk. i'm hesitant to add those docs anywhere else because (A) they only apply on Windows and (B) we currently have no docs which mention EXTRA_SRC. The only place EXTRA_SRC is referenced is in the makefiles and tools/mksqlite3c.tcl. That makes it an "undocumented feature," and we're tempted to keep it undocumented so that it does not become an enforced future maintenance burden. So long as it remains undocumented, we're free to remove or rename it.

An alternative approach, though: the following patch treats declspecs in EXTRA_SRC files identically to how extensions are treated when creating shell.c. Whether or not it will be checked in is still up for discussion with the other devs.

 # Read the source file named $filename and write it into the
-# sqlite3.c output file. The only transformation is the trimming
-# of EOL whitespace.
+# sqlite3.c output file. The only transformations are:
+#
+# 1) Trimming of EOL whitespace.
+#
+# 2) If $stripDeclspec is true, all instances of
+#    __declspec(dllexport) are stripped for the input, as
+#    a workaround for importing sqlite3 extensions on
+#    Windows platforms.
 #
-proc copy_file_verbatim {filename} {
+proc copy_file_verbatim {filename {stripDeclspec 0}} {
   global out
   set in [open $filename rb]
   set tail [file tail $filename]
@@ -369,6 +375,9 @@
   section_comment "Begin EXTRA_SRC file $tail"
   while {![eof $in]} {
     set line [string trimright [gets $in]]
+    if {$stripDeclspec} {
+      set line [string map [list __declspec(dllexport) {}] $line]
+    }
     puts $out $line
   }
   section_comment "End of EXTRA_SRC $tail"
@@ -502,7 +511,7 @@
   copy_file $srcdir/$file
 }
 foreach file $extrasrc {
-  copy_file_verbatim $file
+  copy_file_verbatim $file 1
 }
 
 puts $out \


Example, with that patch in place:

$ cat > foo.c
__declspec(dllexport)
int foo(void){}

$ make sqlite3.c EXTRA_SRC=foo.c
...

$ tail sqlite3.c
/************** End of stmt.c ************************************************/
/************** Begin EXTRA_SRC file foo.c ***********************************/

int foo(void){}

/************** End of EXTRA_SRC foo.c ***************************************/
/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
#endif /* SQLITE_AMALGAMATION */
/************************** End of sqlite3.c ******************************/

(10) By anonymous on 2024-12-08 19:56:58 in reply to 9 [link] [source]

Ok, I saw you already modified Makefile.msc.

I think that for most people that should be enough.

And without an entry in the documentation for EXTRA_SRC that is indeed the only place to put it.

I do hope this undocumented feature will not be removed - I have used a workaround until now but this is much cleaner.