../gnu-classpath-on-macos

在 macOS 上编译 GNU Classpath

Published:

classpath gnu

记录在 macOS Catalina 上编译 GNU Classpath 0.99 的过程。

变更记录

编译环境

准备编译环境和源文件

# 安装 antlr
brew install antlr

# 根目录不可写,重新挂载一下
sudo mount -uw /

# 项目路径
sudo mkdir -p /usr/local/app
sudo chown -R `whoami`:admin /usr/loca/app

# 下载并解压源文件
cd /usr/local/app
wget 'https://ftp.gnu.org/gnu/classpath/classpath-0.99.tar.gz'
tar -xvf classpath-0.99.tar.gz


# 安装路径
sudo mkdir -p /usr/local/classpath
sudo chown -R `whoami`:admin /usr/local/classpath

编译

configure

cd /usr/local/app/classpath-0.99

# configure
./configure --disable-plugin --disable-gtk-peer --disable-gjdoc --disable-examples --disable-gconf-peer --with-glibj=both

没有报错则说明配置成功。

make 第一次

make

一通输出之后,最后输出为

...
java_io_VMConsole.c:80:19: error: use of undeclared identifier 'IUCLC'
  new.c_iflag &= ~TERMIOS_ECHO_IFLAGS;
                  ^
java_io_VMConsole.c:50:30: note: expanded from macro 'TERMIOS_ECHO_IFLAGS'
#define TERMIOS_ECHO_IFLAGS (IUCLC|IXON|IXOFF|IXANY)
                             ^
21 warnings and 1 error generated.
make[2]: *** [java_io_VMConsole.lo] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all-recursive] Error 1

参考 how-to-build-gnu-classpath-and-jamvm

sed -i '/#define/i\#define IUCLC 001000' native/jni/java-io/java_io_VMConsole.c

修改后继续编译

make 第二次

make 

一通输出之后,最后输出为

/bin/sh ../../../libtool --tag=CC   --mode=link gcc -W -Wall -Wmissing-declarations -Wwrite-strings -Wmissing-prototypes -Wno-long-long -Wstrict-prototypes -pedantic -fexceptions -fasynchronous-unwind-tables -g -O2 -version-info 0:0:0 -no-undefined  -o libjavaio.la -rpath /usr/local/classpath/lib/classpath java_io_VMConsole.lo java_io_VMFile.lo java_io_VMObjectInputStream.lo java_io_VMObjectStreamClass.lo ../../../native/jni/classpath/jcl.lo ../../../native/jni/native-lib/libclasspathnative.la
libtool: link: gcc -dynamiclib  -o .libs/libjavaio.0.dylib  .libs/java_io_VMConsole.o .libs/java_io_VMFile.o .libs/java_io_VMObjectInputStream.o .libs/java_io_VMObjectStreamClass.o ../../../native/jni/classpath/.libs/jcl.o   -Wl,-force_load,../../../native/jni/native-lib/.libs/libclasspathnative.a   -O2   -install_name  /usr/local/classpath/lib/classpath/libjavaio.0.dylib -compatibility_version 1 -current_version 1.0 -Wl,-single_module
Undefined symbols for architecture x86_64:
  "___darwin_check_fd_set_overflow", referenced from:
      _waitForReadable in libclasspathnative.a(cpnet.o)
      _waitForWritable in libclasspathnative.a(cpnet.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [libjavaio.la] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all-recursive] Error 1

大概就是有个函数找不到了,为了编译,将相关引用注释掉。

  1. native/jni/native-lib/cpnet.c 文件内 waitForWritable 方法替换为。
static jint waitForWritable(jint fd)
{
//  struct timeval tv;
//  fd_set writeset;
//  int ret;
//  
// 
//  FD_ZERO(&writeset);
//  FD_SET(fd, &writeset);
//  if (socketTimeouts[fd] > 0)
//    {
//      tv.tv_sec = socketTimeouts[fd] / 1000;
//      tv.tv_usec = (socketTimeouts[fd] % 1000) * 1000;
//      ret = select(fd+1, NULL, &writeset, NULL, &tv);
//    }
//  else
//    ret = select(fd+1, NULL, &writeset, NULL, NULL);
//
//  return (ret <= 0) ? -1 : 0;
    return 0;
}
  1. native/jni/native-lib/cpnet.c 文件内 waitForReadable 方法替换为。
static jint waitForReadable(jint fd)
{
//  struct timeval tv;
//  fd_set readset;
//  int ret;
//
//
//  FD_ZERO(&readset);
//  FD_SET(fd, &readset);
//  if (socketTimeouts[fd] > 0)
//    {
//      tv.tv_sec = socketTimeouts[fd] / 1000;
//      tv.tv_usec = (socketTimeouts[fd] % 1000) * 1000;
//      ret = select(fd+1, &readset, NULL, NULL, &tv);
//    }
//  else
//    ret = select(fd+1, &readset, NULL, NULL, NULL);
//
//  return (ret <= 0) ? -1 : 0;
    return 0;
}

make 第三次

继续编译

make

一通输出之后,最后输出为

libtool: link: gcc -dynamiclib  -o .libs/libjavanio.0.dylib  .libs/gnu_java_nio_VMPipe.o .libs/gnu_java_nio_VMChannel.o .libs/gnu_java_nio_VMSelector.o .libs/gnu_java_nio_charset_iconv_IconvDecoder.o .libs/gnu_java_nio_charset_iconv_IconvEncoder.o .libs/java_nio_MappedByteBufferImpl.o .libs/java_nio_VMDirectByteBuffer.o .libs/gnu_java_nio_EpollSelectorImpl.o .libs/gnu_java_nio_KqueueSelectorImpl.o ../../../native/jni/classpath/.libs/jcl.o   -Wl,-force_load,../../../native/jni/native-lib/.libs/libclasspathnative.a  -liconv  -O2   -install_name  /usr/local/classpath/lib/classpath/libjavanio.0.dylib -compatibility_version 1 -current_version 1.0 -Wl,-single_module
Undefined symbols for architecture x86_64:
  "___darwin_check_fd_set_overflow", referenced from:
      _Java_gnu_java_nio_VMChannel_connect in gnu_java_nio_VMChannel.o
      _Java_gnu_java_nio_VMChannel_connect6 in gnu_java_nio_VMChannel.o
      _Java_gnu_java_nio_VMChannel_accept in gnu_java_nio_VMChannel.o
      _helper_put_filedescriptors in gnu_java_nio_VMSelector.o
      _helper_get_filedescriptors in gnu_java_nio_VMSelector.o
      _Java_gnu_java_nio_VMSelector_select in gnu_java_nio_VMSelector.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [libjavanio.la] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all-recursive] Error 1

与上面的报错一直,同理,注释掉相关代码, 看代码发现内部有宏控制,修改 src/config.h.in 文件。

sed -i '/#undef HAVE_CONNECT/i\/\//' src/config.h.in
sed -i '/#undef HAVE_ACCEPT/i\/\//' src/config.h.in

而下方三个需要注释方法体。

_helper_put_filedescriptors in gnu_java_nio_VMSelector.o
_helper_get_filedescriptors in gnu_java_nio_VMSelector.o
_Java_gnu_java_nio_VMSelector_select in gnu_java_nio_VMSelector.o
  1. native/jni/java-nio/gnu_java_nio_VMSelector.c 文件内 helper_put_filedescriptors 方法替换为。
void
helper_put_filedescriptors (JNIEnv * env, jintArray fdArray, fd_set * fds,
			    int *max_fd){
}
  1. native/jni/java-nio/gnu_java_nio_VMSelector.c 文件内 helper_get_filedescriptors 方法替换为。
void
helper_put_filedescriptors (JNIEnv * env, jintArray fdArray, fd_set * fds,
			    int *max_fd){
}
  1. native/jni/java-nio/gnu_java_nio_VMSelector.c 文件内 Java_gnu_java_nio_VMSelector_select 方法替换为。
JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMSelector_select (JNIEnv * env,
				     jclass obj __attribute__ ((__unused__)),
				     jintArray read,
				     jintArray write,
				     jintArray except, jlong timeout)
{
  return 0;
}

make 第四次

重新配置并编译

./configure --disable-plugin --disable-gtk-peer --disable-gjdoc --disable-examples --disable-gconf-peer --with-glibj=both
make

一通输出之后,最后输出为

test -z "/usr/local/classpath/bin" || /usr/local/opt/coreutils/libexec/gnubin/mkdir -p "/usr/local/classpath/bin"
 /usr/local/opt/coreutils/libexec/gnubin/install -c gappletviewer gjarsigner gkeytool gjar gnative2ascii gserialver gjavah grmiregistry gtnameserv gorbd grmid grmic '/usr/local/classpath/bin'
test -z "/usr/local/classpath/share/classpath" || /usr/local/opt/coreutils/libexec/gnubin/mkdir -p "/usr/local/classpath/share/classpath"
 /usr/local/opt/coreutils/libexec/gnubin/install -c -m 644 tools.zip '/usr/local/classpath/share/classpath'
make[2]: Nothing to be done for `install-exec-am'.
make[2]: Nothing to be done for `install-data-am'.

编译成功。

安装

make install 

不出意外 /usr/local/classpath 目录下结构如下

tree -L 3 -d /usr/local/classpath

=>

/usr/local/classpath/
├── bin
├── include
├── lib
   ├── classpath
   └── security
└── share
    ├── classpath
       ├── META-INF
       ├── gnu
       ├── java
       ├── javax
       ├── org
       └── sun
    ├── info
    └── man
        └── man1

16 directories

其他

修改之后的项目仓库 classpath-0.99
此次变更的 commit c9fbfb4