[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Building ncurses 6.5 on MS-Windows with MinGW
From: |
Eli Zaretskii |
Subject: |
Building ncurses 6.5 on MS-Windows with MinGW |
Date: |
Sun, 14 Jul 2024 13:19:27 +0300 |
Hi,
First, thank you very much for developing ncurses.
I've build ncurses 6.5 on MS-Windows using MinGW tools, and needed to
solve several problems as I went about it. I describe these problems
and their solutions below, in the hope that this will be useful.
FYI, here's the configure command I used:
./configure --prefix=d:/usr \
--without-ada \
--with-cxx \
--enable-warnings \
--enable-assertions\
--disable-home-terminfo \
--enable-database \
--enable-sp-funcs \
--enable-term-driver \
--enable-interop \
--disable-termcap \
--without-libtool \
--enable-pc-files \
--with-shared \
--with-normal \
--disable-overwrite \
--disable-widec
The configure options were basically taken from your recommendations
in README.MinGW. The only exception is --disable-widec.
Problem #1: the configure script failed as follows:
checking if you want to use pkg-config... yes
checking for pkg-config... /d/usr/bin/pkg-config
checking for /d/usr/bin/pkg-config library directory... auto
checking for search-list... d \usr\lib\pkgconfig;d \usr\share\pkgconfig
checking for first directory... none
checking for workaround... d
checking if we should install .pc files for /d/usr/bin/pkg-config... yes
configure: error: expected a pathname, not "d"
This happens because my pkg-config is a native MinGW port, so the
command to find search path, viz.:
$ pkg-config pkg-config --variable=pc_path
produces a Windows-style directory list:
D:\usr\lib\pkgconfig;D:\usr\share\pkgconfig
and then the 'tr' command incorrectly thinks that the first directory
is 'd'. My solution was to manually hack the configure script to fix
this like below:
cf_search_path=`"$PKG_CONFIG" --variable=pc_path "$cf_pkg_program"
2>/dev/null | tr ';' ' ' | tr '\' '/'`
which also takes care of converting backslashes to forward slashes.
This got me past the configure step.
Problem #2: several source files cause the compiler to emit warnings
like this one:
./tinfo/make_hash.c: In function 'main':
./tinfo/make_hash.c:439:7: warning: cast discards 'const' qualifier from
pointer target type [-Wcast-qual]
439 | free((void *) name_table[n].ute_name);
| ^
I ignored these warnings.
Problem #3: several places in the code don't support file names with
backslashes, and also use X_OK, which is not supported on MS-Windows
(and usually causes invalid parameter errors). The patches to fix
these are attached at the end of this message.
Problem #4: several test programs, including ncurses.exe, hit an
assertion in win_driver.c:
Assertion failed: term != 0, file ../ncurses/./win32con/win_driver.c, line
2067
In ncurses.exe this happens when I press ESC to return to the main
menu. I traced this to _nc_mingw_tcflush, which insists to find the
input file descriptor in the list of known TERMINAL structures
recorded in _nc_screen_chain. But in the cases this assertion
triggers, the only TERMINAL structure has its Filedes set to 1,
whereas lib_kernel.c:flushinp first calls _nc_mingw_tcflush with the
file descriptor of zero, and that triggers the assertion.
My conclusion, after looking at the code, and also after comparing the
code with win32_driver does to implement tcflush, was that it is not
necessary to insist on finding the descriptor in the _nc_screen_chain
terminals. That's because the code anyway calls
FlushConsoleInputBuffer _only_ for STD_INPUT_HANDLE, basically
disregarding the input descriptor. So I used this change to fix this
problem:
--- ./ncurses/win32con/win_driver.c~0 2023-09-16 19:27:44.000000000 +0300
+++ ./ncurses/win32con/win_driver.c 2024-07-10 16:02:45.735385000 +0300
@@ -612,7 +612,7 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * T
returnCode(result);
}
-#ifdef __MING32__
+#ifdef __MINGW32__
#define SysISATTY(fd) _isatty(fd)
#else
#define SysISATTY(fd) isatty(fd)
@@ -2064,14 +2064,24 @@ _nc_mingw_tcgetattr(int fd, struct termi
int
_nc_mingw_tcflush(int fd, int queue)
{
+#if 0
+ /* This is not needed: we flush stdin anyway, regardless of what
+ FD is connected to, as long as it is a console device. Some
+ programs (e.g., 'ncurses' from the test suite) have only fd = 1
+ in terminals recorded by _nc_screen_chain, so they abort
+ unnecessarily here when flushinp calls us with fd = 0. */
TC_PROLOGUE(fd);
(void) term;
+#else
+ int code = ERR;
+#endif
if (_nc_mingw_isconsole(fd)) {
if (queue == TCIFLUSH) {
BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
if (!b)
return (int) GetLastError();
+ return 0;
}
}
return code;
(This also fixes a typo in "__MING32__", and makes the function return
zero if it succeeds, as mandated by Posix.)
Problem #5: misc/Makefile.in is not prepared to deal with
$PKG_CONFIG_LIBDIR that begins with a Windows drive letters, with the
result that *.pc files are not installed:
/bin/install -c ncurses-config /d/usr/test-ncurses-6.5/bin/ncurses6-config
...skip actual install: no destination was given
I fixed this like below:
--- ./misc/Makefile~ 2024-07-11 08:47:35.466830100 +0300
+++ ./misc/Makefile 2024-07-11 11:17:31.781491900 +0300
@@ -148,7 +148,7 @@
install \
install.libs :: pc-files
@$(SHELL) -c 'case "x$(PKG_CONFIG_LIBDIR)" in \
- x/*) \
+ x/* | x[a-zA-Z]:/*) \
mkdir -p $(DESTDIR)$(PKG_CONFIG_LIBDIR:$(prefix)%=%); \
for name in $(PC_FILES); do \
test -f $$name || continue; \
Problem #6: this caused me the most of headache. The problem is that
ncurses cannot be installed in a staging directory because saying
"make install prefix=FOO" rebuilds the library with FOO hard-coded in
a few files. This is explicitly advised against in INSTALL. Instead,
INSTALL says to use "make install DESTDIR=FOO". But this cannot be
used as-is on Windows, because the Makefile's simply prepend
$(DESTDIR) to the directories derives from $(prefix), and that creates
file names which are invalid on Windows, like d:/foo/bard:/usr/share
(when prefix = d:/usr and DESTDIR = d:/foo/bar). (To try to avoid
this, I originally attempted to use prefix = /d/usr, which MSYS
converts to d:/usr when it invokes MinGW problems, but this caused
other troubles: the literal "/d/usr" string is hardcoded in the
programs, and causes failures because native Windows code doesn't
support such file names.)
(If you want to know why I install in a staging directory, then it's
because that makes it much easier to produce binary archives with only
the build artifacts of the package, which I can then both install
locally under $(prefix) and upload to the ezwinports site where others
can download the prebuilt binaries and use them.)
Eventually, I needed to manually hack all the Makefile's to perform
the replacements such as the one below:
$(DESTDIR)$(bindir)/... => $(DESTDIR)$(bindir:$(prefix)%=%)/...
That is, I told Make to remove $(prefix) from the beginning of each
directory, like $(bindir), thus effectively using DESTDIR as
$(prefix), but without touching $(prefix) itself. This worked, but it
also required me to edit run_tic.in, because it also concatenated
DESTDIR with the various installation directories.
Problem #7: there's no "install-strip" target in the Makefiles. I
solved this with manually stripping the programs and the libraries
after "make install".
This ends my "building ncurses 6.5 with MinGW" saga. Once again,
thanks for developing and maintaining ncurses.
Here are the diffs for the minor issues I mentioned in Problem #3
above:
--- ./include/nc_mingw.h~0 2023-02-25 21:59:24.000000000 +0200
+++ ./include/nc_mingw.h 2024-07-09 15:37:36.866527000 +0300
@@ -79,6 +79,12 @@ NCURSES_EXPORT(int) _nc_gettimeofday(str
#define wcwidth(ucs) _nc_wcwidth((wchar_t)(ucs))
NCURSES_EXPORT(int) _nc_wcwidth(wchar_t);
+/* Newer versions of MSVCRT barf with invalid parameter error when
+ passed X_OK of 1, the value defined on MinGW headers. So we
+ disable it here. */
+#undef X_OK
+#define X_OK 0
+
#ifdef __cplusplus
}
#endif
--- ./ncurses/tinfo/access.c~0 2023-06-25 00:55:09.000000000 +0300
+++ ./ncurses/tinfo/access.c 2024-07-09 15:34:02.017708600 +0300
@@ -93,7 +93,7 @@ _nc_rootname(char *path)
NCURSES_EXPORT(bool)
_nc_is_abs_path(const char *path)
{
-#if defined(__EMX__) || defined(__DJGPP__)
+#if defined(__EMX__) || defined(__DJGPP__) || defined(__MINGW32__)
#define is_pathname(s) ((((s) != 0) && ((s)[0] == '/')) \
|| (((s)[0] != 0) && ((s)[1] == ':')))
#else
@@ -109,7 +109,7 @@ NCURSES_EXPORT(unsigned)
_nc_pathlast(const char *path)
{
const char *test = strrchr(path, '/');
-#ifdef __EMX__
+#if defined __EMX__ || defined __MINGW32__
if (test == 0)
test = strrchr(path, '\\');
#endif
- Building ncurses 6.5 on MS-Windows with MinGW,
Eli Zaretskii <=