Categories: Build Tools and Procedures

Building libffi for Windows x64 with Visual C++

I needed to build the zero variant of the HotSpot JVM for the Windows platform recently. libffi is one of the prerequisites for the zero variant. It provides “a portable, high level programming interface to various calling conventions.” I decided to build libffi/libffi at v3.4.8 since it looks like the latest version. I used a Windows x64 machine for this entire process. Visual C++ and MSYS need to be installed to do this. Launch MSYS2 and get the sources from GitHub:

cd /c/repos
git clone https://github.com/libffi/libffi.git
cd libffi
git checkout v3.4.8

MSYS Prerequisites

Install automake and libtool using these commands:

pacman -S automake
pacman -S libtool

The Visual C++ compiler needs to be available in the path as well. Run cl without any parameters to ensure the compiler is available. It most likely won’t be by default. If it isn’t, add it to the path as follows:

export PATH="/c/PROGRA~1/MIB055~1/2022/Enterprise/VC/Tools/MSVC/14.44.35207/bin/Hostx64/x64/:$PATH"

Note that the name of the Visual C++ linker is link.exe, which clashes with the built in “link” command. Prepending the C++ compiler path means that the built-in link command will not be available. Appending the C++ compiler path means that the linker cannot be invoked without specifying its full path.

Generating the configure file

With the MSYS prerequisites installed, run the autogen.sh script:

user@machine /d/repos/libffi
$ ./autogen.sh

This creates a configure script in the root of the repository. Run it using bash:

$ bash configure \
   CC="/d/repos/libffi/msvcc.sh -m64" \
   CXX="/d/repos/libffi/msvcc.sh -m64" \
   CPPFLAGS="-DFFI_BUILDING_DLL" \
   LD=link CPP="cl -nologo -EP" CXXCPP="cl -nologo -EP" \
   --disable-docs \
   --prefix=/d/temp/libffi

Running configure takes about a minute and a half on my 24-core (32 logical processor) machine with 128GB RAM.

Building the Source Code

Simply run make in the root of the repo. The generated LIB and DLL files should be in the x86_64-w64-mingw32/.libs/ subdirectory of the repo root. There will also be ffi.h and ffitarget.h include files in the x86_64-w64-mingw32/include/ subdirectory of the repo root. These 4 files are typically what will be required by other projects with a libffi dependency (like OpenJDK).

$ ls -1 x86_64-w64-mingw32/.libs/
libffi.la
libffi.lai
libffi_convenience.la
libffi_convenience.lib
libffi-8.dll*
libffi-8.exp
libffi-8.lib

$ ls -1 x86_64-w64-mingw32/include/
ffi.h
ffitarget.h
Makefile

My Motivation for Building libffi

I was trying to configure an OpenJDK build (at commit c3de94cee12471) using this command line:

bash configure --with-jvm-variants=zero --with-debug-level=slowdebug --with-jtreg=/cygdrive/c/java/binaries/jtreg/jtreg-7.5.1+1 --with-gtest=/cygdrive/c/repos/googletest --with-extra-ldflags=-profile --with-boot-jdk=/cygdrive/c/java/binaries/jdk/x64/jdk-24+36
...
checking if hsdis should be bundled... no
checking for --enable-libffi-bundling... disabled, default
checking for LIBFFI... checking for ffi.h... no
configure: error: Could not find libffi!
configure exiting with result code 1

That’s when I found the --with-libffi option in jdk/doc/building.md and cloned the libffi repo.

bash configure --with-jvm-variants=zero --with-debug-level=slowdebug --with-jtreg=/cygdrive/c/java/binaries/jtreg/jtreg-7.5.1+1 --with-gtest=/cygdrive/c/repos/googletest --with-extra-ldflags=-profile --with-boot-jdk=/cygdrive/c/java/binaries/jdk/x64/jdk-24+36 --with-libffi=/cygdrive/d/repos/libffi

configure then failed with this error:

...
checking for --enable-libffi-bundling... disabled, default
checking if libffi works... no
configure: error: Found libffi but could not link and compile with it.
configure exiting with result code 1

This was my hint that I probably need to build libffi first. libffi/README.md at v3.4.8 · libffi/libffi explains that the configure script can be generated by running autogen.sh. I first need to fix the line endings. This copilot prompt “convert all existing files in a repo from windows to unix line endings” gets me the solution:

# Tells Git to convert CRLF to LF on commit
# but not the other way around on checkout.
git config core.autocrlf input

# resets the working directory and re-checks
# out the files using the current core.autocrlf setting
git reset --hard

Now autogen.sh can be executed. I didn’t read the instructions all the way through to see what prerequisites are required. Even so, which ones can I get away without?

user@machine /cygdrive/d/repos/libffi
$ ./autogen.sh
autoreconf-2.71: export WARNINGS=
autoreconf-2.71: Entering directory '.'
autoreconf-2.71: configure.ac: not using Gettext
autoreconf-2.71: running: aclocal -I m4
Can't exec "aclocal": No such file or directory at /usr/share/autoconf2.7/Autom4te/FileUtils.pm line 274.
autoreconf-2.71: error: aclocal failed with exit status: 1

Can’t exec “aclocal” – Search leads to macos – Error ‘Can’t exec “aclocal”‘ with homebrew installed autoreconf on mac – Stack Overflow, which suggests the solution (see Windows OpenJDK Development Environment Setup – Saint’s Log for command line I used to set up my development environment). I install the two prerequisites in Cygwin:

setup-x86_64.exe -q -P automake
setup-x86_64.exe -q -P libtool

For some reason, autogen.sh not only doesn’t work in Cygwin after this but absolutely nothing happens, no error messages and no configure file created, it’s as though I just pressed ENTER. At this point, I went back to the History for make/autoconf/lib-ffi.m4 – openjdk/jdk. The instructions in 8309880: Add support for linking libffi on Windows and Mac · openjdk/jdk@4c18b9e (using MSYS2) were promising: I launched a VS 2022 Developer Command Prompt then ran

C:\software\msys64\ucrt64.exe

Running autogen.sh then reminded me to install the prerequisites the setup in MSYS:

$ ./autogen.sh
autoreconf-2.72: export WARNINGS=
autoreconf-2.72: Entering directory '.'
autoreconf-2.72: configure.ac: not using Gettext
autoreconf-2.72: running: aclocal -I m4
Can't exec "aclocal": No such file or directory at /usr/share/autoconf-2.72/Autom4te/FileUtils.pm line 299.
autoreconf-2.72: error: aclocal failed with exit status: 1

$ pacman -S automake
resolving dependencies...
looking for conflicting packages...

Packages (8) automake1.11-1.11.6-6  automake1.12-1.12.6-6  automake1.13-1.13.4-7  automake1.14-1.14.1-6
             automake1.15-1.15.1-4  automake1.16-1.16.5-1  automake1.17-1.17-1  automake-wrapper-20240607-1

Total Download Size:    3.49 MiB
Total Installed Size:  10.25 MiB

:: Proceed with installation? [Y/n] y
:: Retrieving packages...
 automake1.17-1.17-1-any              535.0 KiB   444 KiB/s 00:01 [###################################] 100%
 automake1.14-1.14.1-6-any            503.1 KiB   391 KiB/s 00:01 [###################################] 100%
 automake1.15-1.15.1-4-any            513.4 KiB   390 KiB/s 00:01 [###################################] 100%
 automake1.12-1.12.6-6-any            503.1 KiB   363 KiB/s 00:01 [###################################] 100%
 automake1.11-1.11.6-6-any            490.2 KiB  1656 KiB/s 00:00 [###################################] 100%
 automake1.13-1.13.4-7-any            501.5 KiB   881 KiB/s 00:01 [###################################] 100%
 automake-wrapper-20240607-1-any        4.3 KiB  8.89 KiB/s 00:00 [###################################] 100%
 automake1.16-1.16.5-1-any            526.3 KiB   223 KiB/s 00:02 [###################################] 100%
 Total (8/8)                            3.5 MiB  1360 KiB/s 00:03 [###################################] 100%
(8/8) checking keys in keyring                                    [###################################] 100%
(8/8) checking package integrity                                  [###################################] 100%
(8/8) loading package files                                       [###################################] 100%
(8/8) checking for file conflicts                                 [###################################] 100%
(8/8) checking available disk space                               [###################################] 100%
:: Processing package changes...
(1/8) installing automake1.11                                     [###################################] 100%
(2/8) installing automake1.12                                     [###################################] 100%
(3/8) installing automake1.13                                     [###################################] 100%
(4/8) installing automake1.14                                     [###################################] 100%
(5/8) installing automake1.15                                     [###################################] 100%
(6/8) installing automake1.16                                     [###################################] 100%
(7/8) installing automake1.17                                     [###################################] 100%
(8/8) installing automake-wrapper                                 [###################################] 100%
:: Running post-transaction hooks...
(1/1) Updating the info directory file...

$ ./autogen.sh
autoreconf-2.72: export WARNINGS=
autoreconf-2.72: Entering directory '.'
autoreconf-2.72: configure.ac: not using Gettext
autoreconf-2.72: running: aclocal -I m4
autoreconf-2.72: configure.ac: tracing
autoreconf-2.72: configure.ac: not using Libtool
autoreconf-2.72: configure.ac: not using Intltool
autoreconf-2.72: configure.ac: not using Gtkdoc
autoreconf-2.72: running: /usr/bin/autoconf-2.72
configure.ac:88: warning: The preprocessor macro `STDC_HEADERS' is obsolete.
configure.ac:88:   Except in unusual embedded environments, you can safely include all
configure.ac:88:   ISO C90 headers unconditionally.
configure.ac:123: warning: The macro 'AC_TRY_COMPILE' is obsolete.
configure.ac:123: You should run autoupdate.
../autoconf-2.72/lib/autoconf/general.m4:2845: AC_TRY_COMPILE is expanded from...
../autoconf-2.72/lib/m4sugar/m4sh.m4:690: _AS_IF_ELSE is expanded from...
../autoconf-2.72/lib/m4sugar/m4sh.m4:697: AS_IF is expanded from...
../autoconf-2.72/lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from...
../autoconf-2.72/lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from...
m4/asmcfi.m4:1: GCC_AS_CFI_PSEUDO_OP is expanded from...
configure.ac:123: the top level
configure.ac:438: warning: LT_PATH_LD is m4_require'd but not m4_defun'd
acinclude.m4:149: LIBFFI_CHECK_LINKER_FEATURES is expanded from...
acinclude.m4:255: LIBFFI_ENABLE_SYMVERS is expanded from...
configure.ac:438: the top level
autoreconf-2.72: running: /usr/bin/autoheader-2.72
autoreconf-2.72: running: automake --add-missing --copy --no-force
configure.ac:31: installing './compile'
configure.ac:19: installing './install-sh'
configure.ac:19: installing './missing'
Makefile.am:39: error: Libtool library used but 'LIBTOOL' is undefined
Makefile.am:39:   The usual way to define 'LIBTOOL' is to add 'LT_INIT'
Makefile.am:39:   to 'configure.ac' and run 'aclocal' and 'autoconf' again.
Makefile.am:39:
Makefile.am:39:   If 'LT_INIT' is in 'configure.ac', make sure
Makefile.am:39:   its definition is in aclocal's search path.
Makefile.am:39:
Makefile.am:39:   If you install Automake in its own prefix,
Makefile.am:39:   you'll need to arrange for the Libtool m4 files
Makefile.am:39:   to be found by aclocal.  For info on this, see:
Makefile.am:39:     https://gnu.org/s/automake/manual/automake.html#Libtool-library-used-but-LIBTOOL-is-undefined
Makefile.am: installing './depcomp'
doc/Makefile.am:3: installing 'doc/mdate-sh'
doc/Makefile.am:3: installing 'doc/texinfo.tex'
autoreconf-2.72: error: automake failed with exit status: 1

$ pacman -S libtool
resolving dependencies...
looking for conflicting packages...

Packages (2) libltdl-2.5.3-1  libtool-2.5.3-1

Total Download Size:   0.43 MiB
Total Installed Size:  2.37 MiB

:: Proceed with installation? [Y/n] y
:: Retrieving packages...
 libltdl-2.5.3-1-x86_64                40.6 KiB  45.4 KiB/s 00:01 [###################################] 100%
 libtool-2.5.3-1-x86_64               403.4 KiB   382 KiB/s 00:01 [###################################] 100%
 Total (2/2)                          444.0 KiB   389 KiB/s 00:01 [###################################] 100%
(2/2) checking keys in keyring                                    [###################################] 100%
(2/2) checking package integrity                                  [###################################] 100%
(2/2) loading package files                                       [###################################] 100%
(2/2) checking for file conflicts                                 [###################################] 100%
(2/2) checking available disk space                               [###################################] 100%
:: Processing package changes...
(1/2) installing libltdl                                          [###################################] 100%
(2/2) installing libtool                                          [###################################] 100%
:: Running post-transaction hooks...
(1/1) Updating the info directory file...

$ ./autogen.sh
autoreconf-2.72: export WARNINGS=
autoreconf-2.72: Entering directory '.'
autoreconf-2.72: configure.ac: not using Gettext
autoreconf-2.72: running: aclocal -I m4
autoreconf-2.72: configure.ac: tracing
autoreconf-2.72: running: libtoolize --copy
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
autoreconf-2.72: configure.ac: not using Intltool
autoreconf-2.72: configure.ac: not using Gtkdoc
autoreconf-2.72: running: aclocal -I m4
autoreconf-2.72: running: /usr/bin/autoconf-2.72
configure.ac:88: warning: The preprocessor macro `STDC_HEADERS' is obsolete.
configure.ac:88:   Except in unusual embedded environments, you can safely include all
configure.ac:88:   ISO C90 headers unconditionally.
configure.ac:123: warning: The macro 'AC_TRY_COMPILE' is obsolete.
configure.ac:123: You should run autoupdate.
../autoconf-2.72/lib/autoconf/general.m4:2845: AC_TRY_COMPILE is expanded from...
../autoconf-2.72/lib/m4sugar/m4sh.m4:690: _AS_IF_ELSE is expanded from...
../autoconf-2.72/lib/m4sugar/m4sh.m4:697: AS_IF is expanded from...
../autoconf-2.72/lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from...
../autoconf-2.72/lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from...
m4/asmcfi.m4:1: GCC_AS_CFI_PSEUDO_OP is expanded from...
configure.ac:123: the top level
autoreconf-2.72: running: /usr/bin/autoheader-2.72
autoreconf-2.72: running: automake --add-missing --copy --no-force
autoreconf-2.72: Leaving directory '.'

$ ls configure
configure

The configure file was created successfully. Now I could run bash configure per the libffi instructions.

mkdir -p /d/temp/libffi

bash configure \
   CC="/d/repos/libffi/msvcc.sh -m64" \
   CXX="/d/repos/libffi/msvcc.sh -m64" \
   CPPFLAGS="-DFFI_BUILDING_DLL" \
   --disable-docs \
   --prefix=/d/temp/libffi

Of course this wasn’t going to just work:

configure: loading site script /etc/config.site
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
continue configure in default builddir "./x86_64-w64-mingw32"
....exec /bin/sh ../configure "--srcdir=.." "--enable-builddir=x86_64-w64-mingw32" "mingw32"
configure: loading site script /etc/config.site
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
checking for gsed... sed
checking for a BSD-compatible install... /usr/bin/install -c
checking whether sleep supports fractional seconds... yes
checking filesystem timestamp resolution... 0.01
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking xargs -n works... yes
checking for gcc... /d/repos/libffi/msvcc.sh -m64
checking whether the C compiler works... no
configure: error: in '/d/repos/libffi/x86_64-w64-mingw32':
configure: error: C compiler cannot create executables
See 'config.log' for more details

The instructions at jdk/make/devkit/createLibffiBundle.sh at c3de94cee12471a11c457c11dd55c547633de5cb · openjdk/jdk look incomplete, compared to those at libffi/libffi at c6f1610509d3d146017d6cc30020ce334bde8425. I added the LD, CPP, and CXXPP values below but got the same error.

bash configure \
   CC="/d/repos/libffi/msvcc.sh -m64" \
   CXX="/d/repos/libffi/msvcc.sh -m64" \
   CPPFLAGS="-DFFI_BUILDING_DLL" \
   LD=link CPP="cl -nologo -EP" CXXCPP="cl -nologo -EP" \
   --disable-docs \
   --prefix=/d/temp/libffi

I tried that command in Cygwin now that a configure file was present:

bash configure \
   CC="/cygdrive/d/repos/libffi/msvcc.sh -m64" \
   CXX="/cygdrive/d/repos/libffi/msvcc.sh -m64" \
   CPPFLAGS="-DFFI_BUILDING_DLL" \
   LD=link CPP="cl -nologo -EP" CXXCPP="cl -nologo -EP" \
   --disable-docs \
   --prefix=/cygdrive/d/temp/libffi

In Cygwin, that command failed with “configure: error: cannot run /bin/sh ./config.sub“. What could be going wrong in the configure script? M365 Copilot prompt: “change build system type in msys2” refers to gcc – Configuration x86_64-pc-msys not supported – Stack Overflow but those flags seem unnecessary given my platform. I tried removing some of the compiler setting flags to no avail:

$ time bash configure CPPFLAGS="-DFFI_BUILDING_DLL" CPP="cl -nologo -EP" CXXCPP="cl -nologo -EP"    --disable-docs    --prefix=/d/temp/libffi
configure: loading site script /etc/config.site
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
continue configure in default builddir "./x86_64-w64-mingw32"
....exec /bin/sh ../configure "--srcdir=.." "--enable-builddir=x86_64-w64-mingw32" "mingw32"
configure: loading site script /etc/config.site
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
checking for gsed... sed
checking for a BSD-compatible install... /usr/bin/install -c
checking whether sleep supports fractional seconds... yes
checking filesystem timestamp resolution... 0.01
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking xargs -n works... yes
checking for gcc... no
checking for cc... no
checking for cl.exe... no
checking for clang... no
configure: error: in '/d/repos/libffi/x86_64-w64-mingw32':
configure: error: no acceptable C compiler found in $PATH
See 'config.log' for more details

The config.log file is in the x86_64-w64-mingw32 folder in the repo root. What I should have verified is that I could run cl.exe in MSYS before trying any of this stuff. That was the primary reason for launch ucrt64.exe from a developer command prompt. Unfortunately, that didn’t work for whatever reason.

user@machine UCRT64 /d/repos/libffi
$ cl
-bash: cl: command not found

user@machine UCRT64 /d/repos/libffi
$ echo $PATH
/ucrt64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl

I tried manually fixing the path as follows but this didn’t work (cl.exe could still not be found):

export PATH="$PATH:/c/Program\ Files/Microsoft\ Visual\ Studio/2022/Enterprise/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64/"

The dir command can show the short name equivalents of a file name, e.g. dir /x C:\Program Files.

dir /x C:\
...
05/24/2025  11:42 AM    <DIR>          PROGRA~1     Program Files
04/09/2025  01:31 AM    <DIR>          PROGRA~2     Program Files (x86)
...

dir /x "C:\Program Files"
11/30/2023  04:40 PM    <DIR>          MIB055~1     Microsoft Visual Studio

Maybe the path will work better with this format?

export PATH="$PATH:/c/PROGRA~1/MIB055~1/2022/Enterprise/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64/"

Sure enough, I could now find cl.exe and the configure script worked!

$ where cl.exe
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.43.34808\bin\Hostx64\x64\cl.exe
$ bash configure \
   CC="/d/repos/libffi/msvcc.sh -m64" \
   CXX="/d/repos/libffi/msvcc.sh -m64" \
   CPPFLAGS="-DFFI_BUILDING_DLL" \
   LD=link CPP="cl -nologo -EP" CXXCPP="cl -nologo -EP" \
   --disable-docs \
   --prefix=/d/temp/libffi
configure: loading site script /etc/config.site
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
continue configure in default builddir "./x86_64-w64-mingw32"
....exec /bin/sh ../configure "--srcdir=.." "--enable-builddir=x86_64-w64-mingw32" "mingw32"
configure: loading site script /etc/config.site
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
checking for gsed... sed
checking for a BSD-compatible install... /usr/bin/install -c
checking whether sleep supports fractional seconds... yes
checking filesystem timestamp resolution... 0.01
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking xargs -n works... yes
checking for gcc... /d/repos/libffi/msvcc.sh -m64
checking whether the C compiler works... yes
checking for C compiler default output file name... conftest.exe
checking for suffix of executables... .exe
checking whether we are cross compiling... no
checking for suffix of object files... obj
checking whether the compiler supports GNU C... no
checking whether /d/repos/libffi/msvcc.sh -m64 accepts -g... yes
checking for /d/repos/libffi/msvcc.sh -m64 option to enable C11 features... unsupported
checking for /d/repos/libffi/msvcc.sh -m64 option to enable C99 features... unsupported
checking for /d/repos/libffi/msvcc.sh -m64 option to enable C89 features... unsupported
checking whether /d/repos/libffi/msvcc.sh -m64 understands -c and -o together... yes
checking whether make supports the include directive... yes (GNU style)
checking dependency style of /d/repos/libffi/msvcc.sh -m64... none
checking whether the compiler supports GNU C++... no
checking whether /d/repos/libffi/msvcc.sh -m64 accepts -g... yes
checking for /d/repos/libffi/msvcc.sh -m64 option to enable C++11 features... unsupported
checking for /d/repos/libffi/msvcc.sh -m64 option to enable C++98 features... unsupported
checking dependency style of /d/repos/libffi/msvcc.sh -m64... none
checking dependency style of /d/repos/libffi/msvcc.sh -m64... none
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking how to print strings... printf
checking for a sed that does not truncate output... /usr/bin/sed
checking for fgrep... /usr/bin/grep -F
checking for non-GNU ld... link
checking if the linker (link) is GNU ld... no
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... no, using cp -pR
checking the maximum length of command line arguments... 8192
checking how to convert x86_64-w64-mingw32 file names to x86_64-w64-mingw32 format... func_convert_file_msys_to_w32
checking how to convert x86_64-w64-mingw32 file names to toolchain format... func_convert_file_msys_to_w32
checking for link option to reload object files... -r
checking for file... file
checking for objdump... objdump
checking how to recognize dependent libraries... file_magic ^x86 archive import|^x86 DLL
checking for dlltool... dlltool
checking how to associate runtime and link libraries... func_cygming_dll_for_implib
checking for ranlib... ranlib
checking for ar... ar
checking for archiver @FILE support... @
checking for strip... strip
checking command to parse /usr/bin/nm -B output from /d/repos/libffi/msvcc.sh -m64 object... ok
checking for sysroot... no
checking for a working dd... /usr/bin/dd
checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
checking for mt... no
checking if : is a manifest tool... no
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for strings.h... no
checking for sys/stat.h... yes
checking for sys/types.h... yes
checking for unistd.h... no
checking for dlfcn.h... no
checking for objdir... .libs
checking for /d/repos/libffi/msvcc.sh -m64 option to produce PIC... -DDLL_EXPORT -DPIC
checking if /d/repos/libffi/msvcc.sh -m64 PIC flag -DDLL_EXPORT -DPIC works... yes
checking if /d/repos/libffi/msvcc.sh -m64 static flag  works... yes
checking if /d/repos/libffi/msvcc.sh -m64 supports -c -o file.obj... yes
checking if /d/repos/libffi/msvcc.sh -m64 supports -c -o file.obj... (cached) yes
checking whether the /d/repos/libffi/msvcc.sh -m64 linker (link) supports shared libraries... yes
checking dynamic linker characteristics... Win32 ld.exe
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... yes
checking how to run the C++ preprocessor... cl -nologo -EP
checking whether the /d/repos/libffi/msvcc.sh -m64 linker (link) supports shared libraries... no
checking for /d/repos/libffi/msvcc.sh -m64 option to produce PIC... -DDLL_EXPORT -DPIC
checking if /d/repos/libffi/msvcc.sh -m64 PIC flag -DDLL_EXPORT -DPIC works... yes
checking if /d/repos/libffi/msvcc.sh -m64 static flag  works... yes
checking if /d/repos/libffi/msvcc.sh -m64 supports -c -o file.obj... yes
checking if /d/repos/libffi/msvcc.sh -m64 supports -c -o file.obj... (cached) yes
checking whether the /d/repos/libffi/msvcc.sh -m64 linker (link) supports shared libraries... no
checking dynamic linker characteristics... Win32 ld.exe
checking how to hardcode library paths into programs... immediate
checking for readelf... readelf
checking size of size_t... 8
checking for C compiler vendor... microsoft
checking whether C compiler accepts  -O2... yes
checking CFLAGS for most reasonable warnings...
checking whether to enable maintainer-specific portions of Makefiles... no
checking for sys/memfd.h... no
checking for memfd_create... no
checking for egrep... (cached) /usr/bin/grep -E
checking for memcpy... no
checking for alloca.h... no
checking size of double... 8
checking size of long double... 8
checking whether byte ordering is bigendian... no
checking assembler .cfi pseudo-op support... no
checking assembler supports pc related relocs... yes
checking whether compiler supports pointer authentication... no
checking for _ prefix in compiled symbols... no
configure: versioning on shared library symbols is no
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating include/Makefile
config.status: creating include/ffi.h
config.status: creating Makefile
config.status: creating testsuite/Makefile
config.status: creating man/Makefile
config.status: creating doc/Makefile
config.status: creating libffi.pc
config.status: creating fficonfig.h
config.status: executing buildir commands
config.status: create top_srcdir/Makefile guessed from local Makefile
config.status: build in x86_64-w64-mingw32 (HOST=)
config.status: executing depfiles commands
config.status: executing libtool commands
config.status: executing include commands
config.status: executing src commands

I could now run make as instructed by the readme. Here is the tail of the resulting output:

...
libtool: link: /d/repos/libffi/msvcc.sh -m64 -o .libs/libffi-8.dll  src/.libs/prep_cif.obj src/.libs/types.obj src/.libs/raw_api.obj src/.libs/java_raw_api.obj src/.libs/closures.obj src/.libs/tramp.obj src/x86/.libs/ffiw64.obj src/x86/.libs/win64_intel.obj   -m64 -O2   `func_echo_all "" | /usr/bin/sed 's/ -lc$//'` -link -dll
libtool: link: linknames=
libtool: link: true
libtool: link: ( cd ".libs" && rm -f "libffi.la" && cp -pR "../libffi.la" "libffi.la" )
make[3]: Leaving directory '/d/repos/libffi/x86_64-w64-mingw32'
make[2]: Leaving directory '/d/repos/libffi/x86_64-w64-mingw32'
make[1]: Leaving directory '/d/repos/libffi/x86_64-w64-mingw32'
MAKE x86_64-pc-mingw64 : 0 * all-configured
make[1]: Entering directory '/d/repos/libffi/x86_64-w64-mingw32'
make[1]: *** No rule to make target 'all-configured'.  Stop.
make[1]: Leaving directory '/d/repos/libffi/x86_64-w64-mingw32'
make: *** [Makefile:3782: all-configured] Error 2

Although the build appeared to have failed, the .DLL, .LIB, and .h files I needed had been generated!

$ ls -1 x86_64-w64-mingw32/.libs/
libffi-8.dll
libffi-8.exp
libffi-8.lib
libffi.la
libffi.lai
libffi_convenience.la
libffi_convenience.lib

I manually copied these files to set up the libffi repo for building OpenJDK (the expected LIB filename does not have the -8 suffix by default). I’m guessing make install or something like that is the proper way to do this but I had what I needed so this was good enough for me.

$ cp -r x86_64-w64-mingw32/.libs lib/
$ cp -r x86_64-w64-mingw32/include/ include/
$ cp lib/libffi-8.lib lib/libffi.lib
$ cp lib/libffi-8.dll lib/libffi.dll

This is the test function OpenJDK’s configure uses to validate the libffi installation.

#include <ffi.h>

int main() {
  ffi_call(NULL, NULL, NULL, NULL);
  return 0;
}

I tested this file to ensure I could compile it. The linking step failed (cl.exe without the -c option).

$ cl -c -I include ffi_test.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.43.34810 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

ffi_test.c

$ cl -I include ffi_test.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.43.34810 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

ffi_test.c
Microsoft (R) Incremental Linker Version 14.43.34810.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:ffi_test.exe
ffi_test.obj
ffi_test.obj : error LNK2019: unresolved external symbol __imp_ffi_call referenced in function main
ffi_test.exe : fatal error LNK1120: 1 unresolved externals

I tried manually running link.exe but this failed because the wrong link.exe is called.

$ where link.exe
C:\software\msys64\usr\bin\link.exe
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.43.34808\bin\Hostx64\x64\link.exe

Prepending the compiler path to $PATH resolved this.

$ cl -I include ffi_test.c -link -libpath:lib libffi.lib
Microsoft (R) C/C++ Optimizing Compiler Version 19.43.34810 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

ffi_test.c
Microsoft (R) Incremental Linker Version 14.43.34810.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:ffi_test.exe
-libpath:lib
libffi.lib
ffi_test.obj

$ ./ffi_test.exe

At this point, things were in good enough shape to build OpenJDK. However, I could not successfully run bash configure ... in Cygwin (to build OpenJDK) now. Perhaps it’s because I had been mucking around with the Cygwin setup. I tried removing automake and libtool but that didn’t fix the problem.

setup-x86_64.exe -?
setup-x86_64.exe -q -x automake
setup-x86_64.exe -q -x libtool

This was when I uninstalled and reinstalled Cygwin to get everything to work again.

Article info



Leave a Reply

Your email address will not be published. Required fields are marked *