win32: handle quoted LIBRARY names in def files

Parse quoted LIBRARY names as a single token and add the default .dll
extension when needed. Allocate the stored name dynamically.

Add a Windows regression test using a quoted name with spaces.
This commit is contained in:
Mounir IDRASSI 2026-07-28 11:01:33 +09:00
parent 85ba3ae8f1
commit 31020bf963
5 changed files with 62 additions and 3 deletions

27
tccpe.c
View File

@ -1775,10 +1775,26 @@ static char *get_token(char **s, char *f)
return p; return p;
} }
/* Read a LIBRARY argument whose quotes may protect whitespace. */
static char *get_libname(char **s, char *f)
{
char *p = trimfront(*s), *e;
if (*p != '"')
return get_token(s, f);
for (e = ++p; *e && *e != '"' && *e != '\r' && *e != '\n'; ++e)
;
if (*e != '"' || (unsigned char)e[1] > ' ')
return NULL;
*s = trimfront(e + 1);
*f = **s;
*e = 0;
return p;
}
static int pe_load_def(TCCState *s1, int fd) static int pe_load_def(TCCState *s1, int fd)
{ {
int state = 0, ret = -1, dllindex = 0, ord; int state = 0, ret = -1, dllindex = 0, ord;
char dllname[80], *buf, *line, *p, *x, next; char *dllname = NULL, *buf, *line, *p, *x, next;
buf = tcc_load_text(fd); buf = tcc_load_text(fd);
if (!buf) if (!buf)
@ -1792,7 +1808,13 @@ static int pe_load_def(TCCState *s1, int fd)
case 0: case 0:
if (0 != stricmp(p, "LIBRARY") || next == '\n') if (0 != stricmp(p, "LIBRARY") || next == '\n')
goto quit; goto quit;
pstrcpy(dllname, sizeof dllname, get_token(&line, &next)); p = get_libname(&line, &next);
if (!p || !*p)
goto quit;
dllname = tcc_malloc(strlen(p) + 5);
strcpy(dllname, p);
if (!*tcc_fileextension(dllname))
strcat(dllname, ".dll");
++state; ++state;
break; break;
case 1: case 1:
@ -1823,6 +1845,7 @@ skip:
} }
ret = 0; ret = 0;
quit: quit:
tcc_free(dllname);
tcc_free(buf); tcc_free(buf);
return ret; return ret;
} }

View File

@ -0,0 +1,21 @@
#ifdef DEF_LIBRARY_DLL
__declspec(dllexport) int def_library_value(void)
{
return 42;
}
#else
#include <stdio.h>
int def_library_value(void);
int main(void)
{
int value = def_library_value();
printf("value: %d\n", value);
return value != 42;
}
#endif

View File

@ -0,0 +1,3 @@
LIBRARY "def library test"
EXPORTS
def_library_value

View File

@ -0,0 +1 @@
value: 42

View File

@ -37,7 +37,7 @@ ifeq ($(CONFIG_bcheck),no)
SKIP += 132_bound_test.test SKIP += 132_bound_test.test
endif endif
ifeq ($(CONFIG_dll),no) ifeq ($(CONFIG_dll),no)
SKIP += 113_btdll.test # no shared lib support yet SKIP += 113_btdll.test 147_def_library.test # no shared lib support yet
endif endif
ifeq (-$(findstring gcc,$(CC))-,--) ifeq (-$(findstring gcc,$(CC))-,--)
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
@ -81,6 +81,9 @@ endif
ifneq (-$(ARCH)-$(CONFIG_WIN32)-,-arm64-yes-) ifneq (-$(ARCH)-$(CONFIG_WIN32)-,-arm64-yes-)
SKIP += 145_winarm64_interlocked.test SKIP += 145_winarm64_interlocked.test
endif endif
ifneq ($(CONFIG_WIN32),yes)
SKIP += 147_def_library.test
endif
# Some tests might need arguments # Some tests might need arguments
ARGS = ARGS =
@ -152,6 +155,14 @@ GEN-ALWAYS =
$(TCC) -bt $1 a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -o $(basename $@).exe && \ $(TCC) -bt $1 a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -o $(basename $@).exe && \
./$(basename $@).exe ./$(basename $@).exe
# Verify quoted LIBRARY names and the default .dll extension in DEF files.
147_def_library.test: T1 = \
cp $(SRC)/147_def_library.def.in 147_def_library.def && \
$(TCC) -D DEF_LIBRARY_DLL -shared $1 -o "def library test.dll" && \
$(TCC) $1 147_def_library.def -o $(basename $@).exe && \
grep -a -q "def library test.dll" $(basename $@).exe && \
./$(basename $@).exe
114_bound_signal.test: FLAGS += -b 114_bound_signal.test: FLAGS += -b
114_bound_signal.test: NORUN = true # tcc -run does not support fork and -b and SELINUX 114_bound_signal.test: NORUN = true # tcc -run does not support fork and -b and SELINUX
115_bound_setjmp.test: FLAGS += -b 115_bound_setjmp.test: FLAGS += -b