Hello,
I have recently tried to build ncurses with MSVC-like tools (cl.exe and
clang-cl.exe) and would like to share what I have encountered.
Configuration
-------------
I was using the following options with configure:
```
--without-debug
--without-profile
--without-progs
--without-tests
--without-ada
--with-cxx
--with-cxx-binding
--enable-exp-win32
--enable-term-driver
--enable-ext-funcs
--disable-ext-colors
--enable-sp-funcs
--enable-interop
--enable-opaque-curses
--enable-opaque-form
--enable-opaque-menu
--enable-opaque-panel
--enable-overwrite
--enable-widec
--disable-lib-suffixes
--disable-termcap
--enable-mixed-case
--disable-symlinks
--enable-pc-files
```
You may see me passing --without-progs and --without-tests. Windows' CRT does
not have getopt.h and does not provide getopt functions. mingw-w64 provides
them.
You also may see me passing --disable-ext-colors. The source file
`ncurses/base/new_pair.c` unconditionally uses `tsearch`, `tfind` and `tdelete`
functions. UCRT's `search.h` does not declare those functions and eventually
link fails. This is not an issue with mingw-w64 since it provides its own
versions of those functions.
Build system
------------
ncurses' build system is just autoconf without automake and libtool, but allows
to use installed libtool script.
The are two ways to build ncurses.
First. Simply use Automake's `compile` and `ar-lib` wrappers for cl.exe and
lib.exe. This way only static libraries can be built, but it may be just fine
in some cases.
Automake-1.17's and earlier `compile` wrapper had a bug which causes ncurses++
build to fail[1]. It was fixed in automake-1.18.
Second. Configure and use libtool script for MSVC-like tools. This allows to
build both shared and static libraries. It works, mostly.
There are a few configuration bugs in libtool which make it produce unusable
.la files[2][3]. A workaround is to set FC=no and F77=no when configuring
libtool.
Issues
------
I had to explicitly pass user32.lib to the linker. Otherwise, link will fail
with undefined reference to MessageBeep function. This is not an issue with
mingw-w64 since compiler passes -luser32 and some others to the linker by
default.
When I tried to build using clang-cl.exe (a clang frontend which understands
cl.exe's command line options) I got many
```
error: call to undeclared function 'FUNCNAME'
```
diagnostics. I summaries all of them in attached ncurses.txt.
All of them can be fixed by including <io.h> or <wchar.h> where appropriate. I
think the reason why this issue was not yet discovered is that mingw-w64's
header files could indirectly include those header files.
cl.exe does not report undeclared functions by default, `-W4` (which can be
compared to -Wall -Wextra) must be passed in order to issue a diagnostic.
Misc
----
In configure's output I see the following:
```
checking if data-only library module links... mv: cannot stat 'conftest.o': No
such file or directory
mv: cannot stat 'conftest.o': No such file or directory
no
```
I believe the issue here is hardcoded .o extension. $OBJEXT probably should be
used instead.
When building and installing from Cygwin, it creates actual symbolic links in
PREFIX/share/terminfo. Native Windows functions cannot read those symbolic
links.
I am aware of a few cases when CRT's non-conformant behavior may cause issues
with ncurses. Let me know if you would like to know about them.
I was using my own script to build ncurses alongside other packages like GNU
libiconv and GNU libintl with MSVC-like tools. It simply invokes `configure` ->
`make` -> `make check` -> `make install DESTDIR=...` in order and takes care of
some important options like -MD. Let me know if you're interested in using this
script to build ncurses with MSVC tools.
- Kirill Makurin
[1] https://lists.gnu.org/archive/html/bug-automake/2025-01/msg00003.html
[2] https://lists.gnu.org/archive/html/bug-libtool/2025-06/msg00000.html
[3] https://lists.gnu.org/archive/html/bug-libtool/2025-06/msg00015.html
H:\releases\ncurses-6.5\ncurses\base\lib_addch.c(229,22): error: call to
undeclared function 'mbrtowc'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
229 | if ((len = (int) mbrtowc(&result,
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_addch.c(229,22): note: did you mean
'mbtowc'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(893,22): note: 'mbtowc' declared here
893 | _ACRTIMP int __cdecl mbtowc(
| ^
1 error generated.
H:\releases\ncurses-6.5\ncurses\base\lib_mouse.c(1111,14): error: call to
undeclared function 'read'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
1111 | res = (int) read(
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_mouse.c(1111,14): note: did you mean
'fread'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdio.h(239,29): note: 'fread' declared here
239 | _ACRTIMP size_t __cdecl fread(
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_mouse.c(1237,14): error: call to
undeclared function 'read'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
1237 | res = (int) read(
| ^
2 errors generated.
H:\releases\ncurses-6.5\ncurses\base\lib_addch.c(229,22): error: call to
undeclared function 'mbrtowc'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
229 | if ((len = (int) mbrtowc(&result,
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_addch.c(229,22): note: did you mean
'mbtowc'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(893,22): note: 'mbtowc' declared here
893 | _ACRTIMP int __cdecl mbtowc(
| ^
1 error generated.
H:\releases\ncurses-6.5\ncurses\base\lib_newterm.c(205,5): error: call to
undeclared function '_setmode'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
205 | _setmode(fileno(_ifp), _O_BINARY);
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_newterm.c(205,5): note: did you mean
'_set_fmode'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(264,26): note: '_set_fmode' declared
here
264 | _ACRTIMP errno_t __cdecl _set_fmode (_In_ int _Mode
);
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_set_term.c(433,5): error: call to
undeclared function '_setmode'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
433 | _setmode(fileno(output), _O_BINARY);
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_set_term.c(433,5): note: did you mean
'_set_fmode'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(264,26): note: '_set_fmode' declared
here
264 | _ACRTIMP errno_t __cdecl _set_fmode (_In_ int _Mode
);
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_slkset.c(87,9): error: call to
undeclared function 'mbrtowc'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
87 | need = mbrtowc(NULL, p, strlen(p), &state);
| ^
H:\releases\ncurses-6.5\ncurses\base\lib_slkset.c(87,9): note: did you mean
'mbtowc'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(893,22): note: 'mbtowc' declared here
893 | _ACRTIMP int __cdecl mbtowc(
| ^
H:\releases\ncurses-6.5\ncurses\widechar\charable.c(42,15): error: call to
undeclared function 'wctob'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
42 | result = (wctob((wint_t) ch) == (int) ch);
| ^
H:\releases\ncurses-6.5\ncurses\widechar\charable.c(42,15): note: did you mean
'wctomb'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(963,22): note: 'wctomb' declared here
963 | _ACRTIMP int __cdecl wctomb(
| ^
H:\releases\ncurses-6.5\ncurses\widechar\charable.c(53,14): error: call to
undeclared function 'wctob'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
53 | result = wctob(ch);
| ^
H:\releases\ncurses-6.5\ncurses\widechar\charable.c(71,14): error: call to
undeclared function 'btowc'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
71 | result = btowc(ch);
| ^
H:\releases\ncurses-6.5\ncurses\widechar\charable.c(71,14): note: did you mean
'mbtowc'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(893,22): note: 'mbtowc' declared here
893 | _ACRTIMP int __cdecl mbtowc(
| ^
3 errors generated.
H:\releases\ncurses-6.5\ncurses\tty\tty_update.c(357,5): error: call to
undeclared function 'wcrtomb'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
357 | PUTC(CHDEREF(ch));
| ^
H:\releases\ncurses-6.5\ncurses\curses.priv.h(1470,20): note: expanded from
macro 'PUTC'
1470 | PUTC_n = (int) wcrtomb(PUTC_buf,
\
| ^
H:\releases\ncurses-6.5\ncurses\tty\tty_update.c(357,5): note: did you mean
'wctomb'?
H:\releases\ncurses-6.5\ncurses\curses.priv.h(1470,20): note: expanded from
macro 'PUTC'
1470 | PUTC_n = (int) wcrtomb(PUTC_buf,
\
| ^
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(963,22): note: 'wctomb' declared here
963 | _ACRTIMP int __cdecl wctomb(
| ^
1 error generated.
H:\releases\ncurses-6.5\ncurses\widechar\lib_slk_wset.c(61,16): error: call to
undeclared function 'wcsrtombs'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
61 | if ((arglen = wcsrtombs(NULL, &str, (size_t) 0, &state)) !=
(size_t) -1) {
| ^
H:\releases\ncurses-6.5\ncurses\widechar\lib_slk_wset.c(61,16): note: did you
mean 'wcstombs'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(1013,15): note: 'wcstombs' declared
here
1013 | _ACRTIMP, wcstombs,
| ^
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\corecrt.h(891,65): note: expanded from macro
'__DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_SIZE'
891 | __DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_SIZE_EX(_DeclSpec,
_FuncName, _FuncName##_s, _DstType, _SalAttributeDst, _DstType, _Dst, _TType1,
_TArg1, _TType2, _TArg2)
| ^
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\corecrt.h(1962,83): note: expanded from macro
'__DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_SIZE_EX'
1962 | _CRT_INSECURE_DEPRECATE(_SecureFuncName) _DeclSpec
size_t __cdecl _FuncName(_SalAttributeDst _DstType *_Dst, _TType1 _TArg1,
_TType2 _TArg2);
|
^
1 error generated.
H:\releases\ncurses-6.5\ncurses\widechar\lib_unget_wch.c(59,17): error: call to
undeclared function 'wcsrtombs'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
59 | result = (int) wcsrtombs(NULL, &tempp, (size_t) 0, state);
| ^
H:\releases\ncurses-6.5\ncurses\widechar\lib_unget_wch.c(59,17): note: did you
mean 'wcstombs'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(1013,15): note: 'wcstombs' declared
here
1013 | _ACRTIMP, wcstombs,
| ^
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\corecrt.h(891,65): note: expanded from macro
'__DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_SIZE'
891 | __DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_SIZE_EX(_DeclSpec,
_FuncName, _FuncName##_s, _DstType, _SalAttributeDst, _DstType, _Dst, _TType1,
_TArg1, _TType2, _TArg2)
| ^
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\corecrt.h(1962,83): note: expanded from macro
'__DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_SIZE_EX'
1962 | _CRT_INSECURE_DEPRECATE(_SecureFuncName) _DeclSpec
size_t __cdecl _FuncName(_SalAttributeDst _DstType *_Dst, _TType1 _TArg1,
_TType2 _TArg2);
|
^
H:\releases\ncurses-6.5\ncurses\widechar\lib_unget_wch.c(61,17): error: call to
undeclared function 'wcrtomb'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
61 | result = (int) wcrtomb(target, source, state);
| ^
H:\releases\ncurses-6.5\ncurses\widechar\lib_unget_wch.c(61,17): note: did you
mean 'wctomb'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(963,22): note: 'wctomb' declared here
963 | _ACRTIMP int __cdecl wctomb(
| ^
H:\releases\ncurses-6.5\ncurses\widechar\lib_unget_wch.c(89,22): error: call to
undeclared function 'wcrtomb'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
89 | IGNORE_RC((int) wcrtomb(string, wch, &state));
| ^
3 errors generated.
H:\releases\ncurses-6.5\ncurses\tinfo\access.c(137,16): error: call to
undeclared function 'access'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
137 | } else if (ACCESS(path, mode) < 0) {
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\access.c(60,27): note: expanded from
macro 'ACCESS'
60 | # define ACCESS(FN, MODE) access((FN), (MODE)&(R_OK|W_OK))
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\access.c(137,16): note: did you mean
'accept'?
H:\releases\ncurses-6.5\ncurses\tinfo\access.c(60,27): note: expanded from
macro 'ACCESS'
60 | # define ACCESS(FN, MODE) access((FN), (MODE)&(R_OK|W_OK))
| ^
C:\Program Files (x86)\Windows
Kits\10\\include\10.0.22000.0\\um\winsock2.h(1631,1): note: 'accept' declared
here
1631 | accept(
| ^
1 error generated.
H:\releases\ncurses-6.5\ncurses\tinfo\lib_print.c(94,20): error: call to
undeclared function 'write'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
94 | result = (int) write(SP_PARM->_ofd, mybuf, need);
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\lib_print.c(94,20): note: did you mean
'fwrite'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdio.h(297,29): note: 'fwrite' declared here
297 | _ACRTIMP size_t __cdecl fwrite(
| ^
1 error generated.
H:\releases\ncurses-6.5\ncurses\tinfo\lib_setup.c(886,2): error: call to
undeclared function '_setmode'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
886 | _setmode(Filedes, _O_BINARY);
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\lib_setup.c(886,2): note: did you mean
'_set_fmode'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdlib.h(264,26): note: '_set_fmode' declared
here
264 | _ACRTIMP errno_t __cdecl _set_fmode (_In_ int _Mode
);
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\lib_tputs.c(139,17): error: call to
undeclared function 'write'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
139 | ssize_t res = write(SP_PARM->_ofd, buf, amount);
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\lib_tputs.c(139,17): note: did you mean
'fwrite'?
C:\Program Files (x86)\Windows
Kits\10\include\10.0.22000.0\ucrt\stdio.h(297,29): note: 'fwrite' declared here
297 | _ACRTIMP size_t __cdecl fwrite(
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\lib_tputs.c(194,10): error: call to
undeclared function 'write'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
194 | if (write(fileno(NC_OUTPUT(SP_PARM)), &tmp, (size_t) 1) ==
-1)
| ^
H:\releases\ncurses-6.5\ncurses\tinfo\lib_tputs.c(199,6): error: call to
undeclared function 'write'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
199 | if (write(fileno(stdout), &tmp, (size_t) 1) == -1)
| ^