2

I am working with a copy of the source code of an ODBC database driver for SQLite that was originally compiled with Visual C++ 6.0 when targeting Windows. I am seeing a linker error of unresolved external symbol when trying to use Visual Studio 2015. Ordinarily, I would just search for the missing function however this case is unusual.

The SQLite ODBC driver source is from http://www.ch-werner.de/sqliteodbc/ and I am looking at creating an ARM64 version of the driver for Windows 10 ARM.

The missing external is normally part of the Standard Library however with Visual Studio 2015, a number of those functions are inline functions defined in header files. I don't have the source for the Microsoft supplied binary component, odbccp32.lib so am unable to recompile it. See also Unresolved ___stdio_common_vsprintf_s, what library has this?

I found this SO post describing the same issue, error LNK2019: unresolved external symbol __vsnwprintf_s referenced in function _StringVPrintfWorkerW@20 , however it was closed and does not have an answer. Reading the comments, there was a suggestion to add an additional library to the linker library list, legacy_stdio_definitions.lib.

However I ended up having to specify two additional libraries, legacy_stdio_definitions.lib and legacy_stdio_wide_specifiers.lib, in order for the link to complete successfully. I have not yet tested the resulting build products.

Reading about while trying to track down the problem, a number of posts suggested similar use of the legacy_stdio_definitions.lib without mentioning the second library which is also needed in my case.

My question

Some people posting about the issue suggested a possible component version incompatibility issue, that the version of odbccp32.lib was an older version that required the external because when it was compiled, the functions were not yet inline.

Is there some kind of build order problem or component version problem that is causing the original link error?

How can I determine the root cause of this linker error?

The link error

link /NODEFAULTLIB /RELEASE /NOLOGO /MACHINE:IX86  /SUBSYSTEM:WINDOWS /DLL sqlite3odbc.obj sqlite3.obj sqlite3odbc.res  -def:sqlite3odbc.def -out:sqlite3odbc.dll msvcrt.lib vcruntime.lib ucrt.lib odbccp32.lib kernel32.lib  user32.lib comdlg32.lib
sqlite3odbc.def(2) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
sqlite3odbc.def(3) : warning LNK4017: SEGMENTS statement not supported for the target platform; ignored
sqlite3odbc.def(4) : warning LNK4017: DLL_TEXT statement not supported for the target platform; ignored
sqlite3odbc.def(5) : warning LNK4017: INIT_TEXT statement not supported for the target platform; ignored
   Creating library sqlite3odbc.lib and object sqlite3odbc.exp
odbccp32.lib(dllload.obj) : error LNK2019: unresolved external symbol __vsnwprintf_s referenced in function _StringCchPrintfW
sqlite3odbc.dll : fatal error LNK1120: 1 unresolved externals
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\link.EXE"' : return code '0x460'
Stop.

When I modify the linker library list by adding legacy_stdio_definitions.lib, I see the following error:

link /NODEFAULTLIB /RELEASE /NOLOGO /MACHINE:IX86  /SUBSYSTEM:WINDOWS /DLL sqlite3odbc.obj sqlite3.obj sqlite3odbc.res  -def:sqlite3odbc.def -out:sqlite3odbc.dll msvcrt.lib vcruntime.lib ucrt.lib odbccp32.lib kernel32.lib  user32.lib comdlg32.lib legacy_stdio_definitions.lib
sqlite3odbc.def(2) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
sqlite3odbc.def(3) : warning LNK4017: SEGMENTS statement not supported for the target platform; ignored
sqlite3odbc.def(4) : warning LNK4017: DLL_TEXT statement not supported for the target platform; ignored
sqlite3odbc.def(5) : warning LNK4017: INIT_TEXT statement not supported for the target platform; ignored
   Creating library sqlite3odbc.lib and object sqlite3odbc.exp
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2001: unresolved external symbol ___PLEASE_LINK_WITH_legacy_stdio_wide_specifiers.lib
sqlite3odbc.dll : fatal error LNK1120: 1 unresolved externals
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\link.EXE"' : return code '0x460'
Stop.

When I change the library list for the linker, I then get the original linker error:

odbccp32.lib(dllload.obj) : error LNK2019: unresolved external symbol __vsnwprintf_s referenced in function _StringCchPrintfW
sqlite3odbc.dll : fatal error LNK1120: 1 unresolved externals

If I specify both libraries, legacy_stdio_definitions.lib and legacy_stdio_wide_specifiers.lib, the link completes successfully. I have not yet tested the resulting build products.

The version of the nmake file that compiles and links successfully is:

# VC++ 6 Makefile
# uses the SQLite3 amalgamation source which must
# be unpacked below in the same folder as this makefile
# Change History
#   2021-10-07 : R Chambers     : replace -GX CFLAGS with -EHSC
#   2021-10-07 : R Chambers     : added additional C Runtime libraries

CC=     cl
LN=     link
RC=     rc

!IF "$(DEBUG)" == "1"
LDEBUG=     /DEBUG
CDEBUG=     -Zi
!ELSE
LDEBUG=     /RELEASE
!ENDIF

# 2021-10-07 RC: -GX flag is deprecated.
#                Use /EHsc for exception handling behavior
# 2021-10-07 RC: add libraries vcruntime.lib ucrt.lib to DLLLFLAGS
#                see https://devblogs.microsoft.com/cppblog/introducing-the-universal-crt/
# 2021-10-07 RC: add libraries legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib
#                to correct link error LNK2019: unresolved external with odbccp32.lib
#                error LNK2019: unresolved external symbol __vsnwprintf_s referenced in function _StringCchPrintfW
#                added new definition EXELIBS
CFLAGS=     -I. -Gs -EHsc -W2 -D_WIN32 -D_DLL -nologo $(CDEBUG) \
        -DHAVE_SQLITE3COLUMNTABLENAME=1 \
        -DHAVE_SQLITE3PREPAREV2=1 \
        -DHAVE_SQLITE3VFS=1 \
        -DHAVE_SQLITE3LOADEXTENSION=1 \
        -DSQLITE_ENABLE_COLUMN_METADATA=1 \
        -DWITHOUT_SHELL=1
CFLAGSEXE=  -I. -Gs -EHsc -W2 -D_WIN32 -nologo $(CDEBUG)
DLLLFLAGS=  /NODEFAULTLIB $(LDEBUG) /NOLOGO /MACHINE:IX86 \
        /SUBSYSTEM:WINDOWS /DLL
DLLLIBS=    msvcrt.lib vcruntime.lib ucrt.lib odbccp32.lib kernel32.lib \
        user32.lib comdlg32.lib \
        legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib
EXELIBS=    odbc32.lib odbccp32.lib kernel32.lib user32.lib \
        legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib
DRVDLL=     sqlite3odbc.dll

OBJECTS=    sqlite3odbc.obj sqlite3.obj

.c.obj:
        $(CC) $(CFLAGS) /c $<

all:        $(DRVDLL) inst.exe uninst.exe adddsn.exe remdsn.exe \
        addsysdsn.exe remsysdsn.exe SQLiteODBCInstaller.exe

clean:
        del *.obj
        del *.res
        del *.exp
        del *.ilk
        del *.pdb
        del *.res
        del resource3.h
        del *.exe
        cd ..

uninst.exe: inst.exe
        copy inst.exe uninst.exe

inst.exe:   inst.c
        $(CC) $(CFLAGSEXE) inst.c $(EXELIBS)

remdsn.exe: adddsn.exe
        copy adddsn.exe remdsn.exe

adddsn.exe: adddsn.c
        $(CC) $(CFLAGSEXE) adddsn.c $(EXELIBS)

remsysdsn.exe:  adddsn.exe
        copy adddsn.exe remsysdsn.exe

addsysdsn.exe:  adddsn.exe
        copy adddsn.exe addsysdsn.exe

fixup.exe:  fixup.c
        $(CC) $(CFLAGSEXE) fixup.c

mkopc3.exe: mkopc3.c
        $(CC) $(CFLAGSEXE) mkopc3.c

SQLiteODBCInstaller.exe:    SQLiteODBCInstaller.c
        $(CC) $(CFLAGSEXE) SQLiteODBCInstaller.c \
        kernel32.lib user32.lib

sqlite3odbc.c:  resource3.h

sqlite3odbc.res:    sqlite3odbc.rc resource3.h
        $(RC) -I. -fo sqlite3odbc.res -r sqlite3odbc.rc

sqlite3odbc.dll:    $(OBJECTS) sqlite3odbc.res
        $(LN) $(DLLLFLAGS) $(OBJECTS) sqlite3odbc.res \
        -def:sqlite3odbc.def -out:$@ $(DLLLIBS)

VERSION_C:  fixup.exe VERSION
        .\fixup < VERSION > VERSION_C . ,

resource3.h:    resource.h.in VERSION_C fixup.exe
        .\fixup < resource.h.in > resource3.h \
            --VERS-- @VERSION \
            --VERS_C-- @VERSION_C

The above nmake file is executed by the following Windows CMD batch file:

echo off

rem Windows command batch file to run
rem the make file for the ADO SQLite driver.

rem set the Visual Studio compiler path below.
rem the path will vary depending on the compiler version.
rem this path is to the proper vcvars batch file needed
rem for the target processor.

set COMPILER="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC"
set PATH=%COMPILER%\bin;%PATH%

echo Run the nmake file for the ADO SQLite driver.

rem we need to have the latest version of the SQLite
rem source files. if the files don't exist then nothing
rem to do so exit with an error message.

if not exist sqlite3.c goto nofile
if not exist sqlite3.h goto nofile

rem set the Visual Studio environment properly
rem for x86. for other targets there are other
rem options such as x64, arm, etc.
rem get list of Windows SDK installed by looking
rem at the list displayed when modifying Visual Studio
rem install from Control panel -> Apps & features
rem look at the Individual components tab.
rem for Visual Studio 2015
rem    Windows 10 - 10.0.14393.0
rem    Windows 8.1 - 8.1

call %COMPILER%\vcvarsall.bat x86 10.0.14393.0

rem nmake -f sqlite3odbc.mak clean
nmake -f sqlite3odbc.mak

goto fini

:nofile

echo Needed SQLite source files not found.
echo Provide sqlite3.c and sqlite3.h source files to compile.

:fini

pause

Uncomfortable with this workaround

At least one person posted that they had some builds that worked fine and others where the addition of the library was needed. This implies a component version problem in which some of the builds used a version of odbccp32.lib that doesn't need the additional legacy_stdio_definitions.lib library and some that do.

The reason I mention a component version problem is because I've read of at least one post where this possibility was raised. With Visual Studio 2015, a number of functions were written to be inline so if a component was created with an earlier compiler, it may be expecting the function to be an available external.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106

0 Answers0