8309880: Add support for linking libffi on Windows and Mac

Co-authored-by: Aleksey Shipilev <shade@openjdk.org>
Co-authored-by: Jorn Vernee <jvernee@openjdk.org>
Reviewed-by: erikj
This commit is contained in:
Jorn Vernee 2023-06-14 12:03:42 +00:00
parent 1d1ed0d8f7
commit 4c18b9e1fa
7 changed files with 126 additions and 30 deletions

View File

@ -57,7 +57,11 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
if test "x${with_libffi}" != x; then if test "x${with_libffi}" != x; then
LIBFFI_LIB_PATH="${with_libffi}/lib" LIBFFI_LIB_PATH="${with_libffi}/lib"
if test "x${OPENJDK_TARGET_OS}" != "xwindows"; then
LIBFFI_LIBS="-L${with_libffi}/lib -lffi" LIBFFI_LIBS="-L${with_libffi}/lib -lffi"
else
LIBFFI_LIBS="${with_libffi}/lib/libffi.lib"
fi
LIBFFI_CFLAGS="-I${with_libffi}/include" LIBFFI_CFLAGS="-I${with_libffi}/include"
LIBFFI_FOUND=yes LIBFFI_FOUND=yes
fi fi
@ -67,7 +71,11 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
fi fi
if test "x${with_libffi_lib}" != x; then if test "x${with_libffi_lib}" != x; then
LIBFFI_LIB_PATH="${with_libffi_lib}" LIBFFI_LIB_PATH="${with_libffi_lib}"
if test "x${OPENJDK_TARGET_OS}" != "xwindows"; then
LIBFFI_LIBS="-L${with_libffi_lib} -lffi" LIBFFI_LIBS="-L${with_libffi_lib} -lffi"
else
LIBFFI_LIBS="${with_libffi_lib}/libffi.lib"
fi
LIBFFI_FOUND=yes LIBFFI_FOUND=yes
fi fi
# Do not try pkg-config if we have a sysroot set. # Do not try pkg-config if we have a sysroot set.
@ -106,12 +114,13 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
AC_MSG_ERROR([Could not find libffi! $HELP_MSG]) AC_MSG_ERROR([Could not find libffi! $HELP_MSG])
fi fi
AC_MSG_CHECKING([if libffi works])
AC_LANG_PUSH(C) AC_LANG_PUSH(C)
OLD_CFLAGS="$CFLAGS" OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $LIBFFI_CFLAGS" CFLAGS="$CFLAGS $LIBFFI_CFLAGS"
OLD_LIBS="$LIBS" OLD_LIBS="$LIBS"
LIBS="$LIBS $LIBFFI_LIBS" LIBS="$LIBS $LIBFFI_LIBS"
AC_MSG_CHECKING([if libffi works])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <ffi.h>], AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <ffi.h>],
[ [
ffi_call(NULL, NULL, NULL, NULL); ffi_call(NULL, NULL, NULL, NULL);
@ -120,9 +129,6 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
[LIBFFI_WORKS=yes], [LIBFFI_WORKS=yes],
[LIBFFI_WORKS=no] [LIBFFI_WORKS=no]
) )
CFLAGS="$OLD_CFLAGS"
LIBS="$OLD_LIBS"
AC_LANG_POP(C)
AC_MSG_RESULT([$LIBFFI_WORKS]) AC_MSG_RESULT([$LIBFFI_WORKS])
if test "x$LIBFFI_WORKS" = xno; then if test "x$LIBFFI_WORKS" = xno; then
@ -130,39 +136,71 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
AC_MSG_ERROR([Found libffi but could not link and compile with it. $HELP_MSG]) AC_MSG_ERROR([Found libffi but could not link and compile with it. $HELP_MSG])
fi fi
# Check if FFI_GO_CLOSURES is properly defined. On some distributions, notably MacOS AArch64,
# ffitarget.h (included from ffi.h) does not explicitly define FFI_GO_CLOSURES. This makes the
# further include of ffi.h trigger the "FFI_GO_CLOSURES is undefined" warning, which fails
# the build when warnings are fatal.
AC_MSG_CHECKING([for FFI_GO_CLOSURES definition])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <ffi.h>
#ifndef FFI_GO_CLOSURES
#error "FFI_GO_CLOSURES is not defined"
#endif
][])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no, defining])
LIBFFI_CFLAGS="$LIBFFI_CFLAGS -DFFI_GO_CLOSURES=0"
]
)
CFLAGS="$OLD_CFLAGS"
LIBS="$OLD_LIBS"
AC_LANG_POP(C)
# Find the libffi.so.X to bundle # Find the libffi.so.X to bundle
if test "x${ENABLE_LIBFFI_BUNDLING}" = "xtrue"; then if test "x${ENABLE_LIBFFI_BUNDLING}" = "xtrue"; then
if test "x${OPENJDK_TARGET_OS}" = "xmacosx"; then
LIBFFI_LIB_FILE_NAME=libffi.?.dylib
elif test "x${OPENJDK_TARGET_OS}" = "xwindows"; then
LIBFFI_LIB_FILE_NAME=libffi.dll
else
LIBFFI_LIB_FILE_NAME=libffi.so.?
fi
AC_MSG_CHECKING([for libffi lib file location]) AC_MSG_CHECKING([for libffi lib file location])
if test "x${LIBFFI_LIB_PATH}" != x; then if test "x${LIBFFI_LIB_PATH}" != x; then
if test -e ${LIBFFI_LIB_PATH}/libffi.so.?; then if test -e ${LIBFFI_LIB_PATH}/${LIBFFI_LIB_FILE_NAME}; then
LIBFFI_LIB_FILE="${LIBFFI_LIB_PATH}/libffi.so.?" LIBFFI_LIB_FILE="${LIBFFI_LIB_PATH}/${LIBFFI_LIB_FILE_NAME}"
else else
AC_MSG_ERROR([Could not locate libffi.so.? for bundling in ${LIBFFI_LIB_PATH}]) AC_MSG_ERROR([Could not locate ${LIBFFI_LIB_FILE_NAME} for bundling in ${LIBFFI_LIB_PATH}])
fi fi
else else
# If we don't have an explicit path, look in a few obvious places # If we don't have an explicit path, look in a few obvious places
if test "x${OPENJDK_TARGET_CPU}" = "xx86"; then if test "x${OPENJDK_TARGET_CPU}" = "xx86"; then
if test -e ${SYSROOT}/usr/lib/libffi.so.? ; then if test -e ${SYSROOT}/usr/lib/${LIBFFI_LIB_FILE_NAME} ; then
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/libffi.so.?" LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/${LIBFFI_LIB_FILE_NAME}"
elif test -e ${SYSROOT}/usr/lib/i386-linux-gnu/libffi.so.? ; then elif test -e ${SYSROOT}/usr/lib/i386-linux-gnu/${LIBFFI_LIB_FILE_NAME} ; then
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/i386-linux-gnu/libffi.so.?" LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/i386-linux-gnu/${LIBFFI_LIB_FILE_NAME}"
else else
AC_MSG_ERROR([Could not locate libffi.so.? for bundling]) AC_MSG_ERROR([Could not locate ${LIBFFI_LIB_FILE_NAME} for bundling])
fi fi
elif test "x${OPENJDK_TARGET_CPU}" = "xx86_64" || test "x${OPENJDK_TARGET_CPU}" = "xaarch64"; then elif test "x${OPENJDK_TARGET_CPU}" = "xx86_64" || test "x${OPENJDK_TARGET_CPU}" = "xaarch64"; then
if test -e ${SYSROOT}/usr/lib64/libffi.so.? ; then if test -e ${SYSROOT}/usr/lib64/${LIBFFI_LIB_FILE_NAME} ; then
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib64/libffi.so.?" LIBFFI_LIB_FILE="${SYSROOT}/usr/lib64/${LIBFFI_LIB_FILE_NAME}"
elif test -e ${SYSROOT}/usr/lib/x86_64-linux-gnu/libffi.so.? ; then elif test -e ${SYSROOT}/usr/lib/x86_64-linux-gnu/${LIBFFI_LIB_FILE_NAME} ; then
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/x86_64-linux-gnu/libffi.so.?" LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/x86_64-linux-gnu/${LIBFFI_LIB_FILE_NAME}"
else else
AC_MSG_ERROR([Could not locate libffi.so.? for bundling]) AC_MSG_ERROR([Could not locate ${LIBFFI_LIB_FILE_NAME} for bundling])
fi fi
else else
# Fallback on the default /usr/lib dir # Fallback on the default /usr/lib dir
if test -e ${SYSROOT}/usr/lib/libffi.so.? ; then if test -e ${SYSROOT}/usr/lib/${LIBFFI_LIB_FILE_NAME} ; then
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/libffi.so.?" LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/${LIBFFI_LIB_FILE_NAME}"
else else
AC_MSG_ERROR([Could not locate libffi.so.? for bundling]) AC_MSG_ERROR([Could not locate ${LIBFFI_LIB_FILE_NAME} for bundling])
fi fi
fi fi
fi fi

View File

@ -38,6 +38,38 @@
# Note that the libtool and texinfo packages are needed to build libffi # Note that the libtool and texinfo packages are needed to build libffi
# $ sudo apt install libtool texinfo # $ sudo apt install libtool texinfo
# Note that while the build system supports linking against libffi on Windows (x64),
# I couldn't get this script working with a Windows devkit, and instead had to manually create
# a libffi bundle for Windows. The steps I took were as follows:
#
# 1. run 'x64 Native Tools Command Prompt for VS 2022'. After that, cl.exe and link.exe should be on path
#
# 2. in the same shell, run `ucrt64` (this is one of the shell environments that comes with MSYS2).
# This should carry over the environment set up by the VS dev prompt into the ucrt64 prompt.
#
# 3. then, in the libffi repo root folder:
# 3.a run `autogen.sh`
# 3.b run:
# ```
# bash configure \
# CC="/path/to/libffi/msvcc.sh -m64" \
# CXX="/path/to/libffi/msvcc.sh -m64" \
# CPPFLAGS="-DFFI_BUILDING_DLL" \
# --disable-docs \
# --prefix=<install dest>
# ```
# (`<install dest>` can be whatever you like. That's what you point `--with-libffi` to).
#
# 4. run `make install`. This should create the `<install dest>` directory with the files:
# `include/ffi.h`, `include/ffitarget.h`, `lib/libffi.dll`. It also creates a `lib/libffi.lib` file,
# but it is of the wrong file type, `DLL` rather than `LIBRARY`.
#
# 5. Manually create a working `.lib` file (in the <install dest>/lib dir):
# 5.a use `dumpbin /exports libffi.dll` to get a list of exported symbols
# 5.b put them in a `libffi.def` file: `EXPORTS` on the first line, then a symbol on each line following
# 5.c run `lib /def:libffi.def /machine:x64 /out:libffi.lib` to create the right `.lib` file (`lib` is a visual studio tool)
#
LIBFFI_VERSION=3.4.2 LIBFFI_VERSION=3.4.2
BUNDLE_NAME=libffi-$LIBFFI_VERSION.tar.gz BUNDLE_NAME=libffi-$LIBFFI_VERSION.tar.gz
@ -49,6 +81,7 @@ SRC_DIR="$OUTPUT_DIR/src"
DOWNLOAD_DIR="$OUTPUT_DIR/download" DOWNLOAD_DIR="$OUTPUT_DIR/download"
INSTALL_DIR="$OUTPUT_DIR/install" INSTALL_DIR="$OUTPUT_DIR/install"
IMAGE_DIR="$OUTPUT_DIR/image" IMAGE_DIR="$OUTPUT_DIR/image"
OS_NAME=$(uname -s)
USAGE="$0 <devkit dir>" USAGE="$0 <devkit dir>"
@ -81,8 +114,33 @@ cd $LIBFFI_DIR
if [ ! -e $LIBFFI_DIR/configure ]; then if [ ! -e $LIBFFI_DIR/configure ]; then
bash ./autogen.sh bash ./autogen.sh
fi fi
case $OS_NAME in
Linux)
CC=$DEVKIT_DIR/bin/gcc
CXX=$DEVKIT_DIR/bin/g++
# For Linux/x86 it's under /lib/ instead of /lib64/
LIB_FOLDER=lib64
LIB_NAME=libffi.so*
;;
Darwin)
CC=$DEVKIT_DIR/Xcode/Contents/Developer/usr/bin/gcc
CXX=$DEVKIT_DIR/Xcode/Contents/Developer/usr/bin/gcc
LIB_FOLDER=lib
LIB_NAME=libffi.*.dylib
;;
*)
echo " Unsupported OS: $OS_NAME"
exit 1
;;
esac
# For Linux/x86, add --build=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 # For Linux/x86, add --build=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32
bash ./configure --prefix=$INSTALL_DIR CC=$DEVKIT_DIR/bin/gcc CXX=$DEVKIT_DIR/bin/g++ bash ./configure \
--disable-docs \
--prefix=$INSTALL_DIR \
CC=$CC \
CXX=$CXX
# Run with nice to keep system usable during build. # Run with nice to keep system usable during build.
nice make $MAKE_ARGS install nice make $MAKE_ARGS install
@ -90,10 +148,9 @@ nice make $MAKE_ARGS install
mkdir -p $IMAGE_DIR mkdir -p $IMAGE_DIR
# Extract what we need into an image # Extract what we need into an image
if [ ! -e $IMAGE_DIR/lib/libffi.so ]; then if [ ! -e $IMAGE_DIR/lib/libffi.so ]; then
echo "Copying libffi.so* to image" echo "Copying ${LIB_NAME} to image"
mkdir -p $IMAGE_DIR/lib mkdir -p $IMAGE_DIR/lib
# For Linux/x86 it's under /lib/ instead of /lib64/ cp -a $INSTALL_DIR/${LIB_FOLDER}/${LIB_NAME} $IMAGE_DIR/lib/
cp -a $INSTALL_DIR/lib64/libffi.so* $IMAGE_DIR/lib/
fi fi
if [ ! -e $IMAGE_DIR/include/ ]; then if [ ! -e $IMAGE_DIR/include/ ]; then
echo "Copying include to image" echo "Copying include to image"

View File

@ -228,6 +228,7 @@ ifeq ($(ENABLE_FALLBACK_LINKER), true)
LDFLAGS := $(LDFLAGS_JDKLIB) \ LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \ $(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(LIBFFI_LIBS), \ LIBS := $(LIBFFI_LIBS), \
LIBS_windows := $(LIBFFI_LIBS) ws2_32.lib, \
)) ))
TARGETS += $(BUILD_LIBFALLBACKLINKER) TARGETS += $(BUILD_LIBFALLBACKLINKER)

View File

@ -32,10 +32,6 @@
#define SUPPORT_MONITOR_COUNT #define SUPPORT_MONITOR_COUNT
#ifdef __APPLE__
#define FFI_GO_CLOSURES 0
#endif
#include <ffi.h> #include <ffi.h>
// Indicates whether the C calling conventions require that // Indicates whether the C calling conventions require that

View File

@ -28,6 +28,7 @@
#include <ffi.h> #include <ffi.h>
#include <errno.h> #include <errno.h>
#include <stdint.h>
#ifdef _WIN64 #ifdef _WIN64
#include <Windows.h> #include <Windows.h>
#include <Winsock2.h> #include <Winsock2.h>

View File

@ -25,6 +25,7 @@
* @test * @test
* @enablePreview * @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED" * @requires jdk.foreign.linker != "UNSUPPORTED"
* @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK")
* @modules java.base/jdk.internal.foreign * @modules java.base/jdk.internal.foreign
* @build NativeTestHelper CallGeneratorHelper TestUpcallBase * @build NativeTestHelper CallGeneratorHelper TestUpcallBase
* *

View File

@ -26,6 +26,7 @@
* @enablePreview * @enablePreview
* @library ../ * @library ../
* @requires jdk.foreign.linker != "UNSUPPORTED" * @requires jdk.foreign.linker != "UNSUPPORTED"
* @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK")
* @modules java.base/jdk.internal.foreign * @modules java.base/jdk.internal.foreign
* @run testng/othervm * @run testng/othervm
* --enable-native-access=ALL-UNNAMED * --enable-native-access=ALL-UNNAMED
@ -39,6 +40,7 @@
* @enablePreview * @enablePreview
* @library ../ * @library ../
* @requires jdk.foreign.linker != "UNSUPPORTED" * @requires jdk.foreign.linker != "UNSUPPORTED"
* @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK")
* @modules java.base/jdk.internal.foreign * @modules java.base/jdk.internal.foreign
* @run testng/othervm * @run testng/othervm
* --enable-native-access=ALL-UNNAMED * --enable-native-access=ALL-UNNAMED