Wednesday, July 12, 2006

Java-Readline on Mac OS X Update

EDIT 11-30-2006: The binary files linked below are now compiled as Universal Binaries. I have no access to an Intel machine, so I would appreciate it if someone could test it and post a comment on how it worked. In order to compile as universal binaries, you must have the latest version of XCode installed, and follow the instructions in red below

DarwinPorts is a great project, but I hate using when I don't have to. Mac OS X (at least Tiger does) comes with a readline compatibity already installed - so I have updated these instructions so that you can create a java-readline installation WITHOUT installing DarwinPorts.

The steps are a bit more involved...but here they are:

Download the libreadline-java source from the project site.

Unpackage.

In the source root, edit Makefile and make the following changes:
  • Add JAVA_HOME = /Library/Java/Home below the line # Operating system dependent
  • Make the JAVANATINC variable read $(JAVA_HOME)/include
  • Change LD_LIBRARY_PATH to be DYLD_LIBRARY_PATH

Now, edit src/native/Makefile and change the following:
  • Change the LIBPATH variable to be empty
  • Change the CFLAGS to -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc -fno-common -DMAC_OS
  • Change $(CC) -shared (OBJECTS) $(LIBPATH) $($(TG)_LIBS) -o $@ to $(CC) -bundle -flat_namespace -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc $(OBJECTS) $(LIBPATH) $($(TG)_LIBS) -o $@
  • change the JavaReadline_LIBS variable to be -lreadline -ltermcap

Now, you need to edit src/native/org_gnu_readline_Readline.c and make the following changes:
  • On lines 98, 114, 213, and 224, change #ifdef JavaReadline to #if defined JavaReadline && !defined MAC_OS
  • On lines 216, 235, and 475, change #ifdef JavaEditline to #if defined JavaEditline || defined MAC_OS

Now, you can run make, and you will end up with libJavaReadline.so and libreadline-java.jar.

Rename libJavaReadline.so to libJavaReadline.jnilib.

Move libJavaReadline.jnilib and libreadline-java.jar to /Library/Java/Extensions to install it and have it available to all java processes.

To test, run java test.ReadlineTest from the command line.

Have fun! Now, you can install HenPlus on Mac OS X easily!

If you are lazy, you can try out the pre-compiled binaries that I have available here - after unzipping, just move the two files (not the entire folder) into your /Library/Java/Extensions directory. NOTE: these *may* only work on OS X 10.4 and up - I have only tested them on that platform, and they are *not* universal binaries - PPC only.

10 comments:

Ryan said...

Has anybody been able to get this to work on an Intel based machine? I followed Nathan's procedure and my `make` spits out this:

cd src ; make JAVAC="javac" JC_FLAGS="" java
javac -d ../build `find . -name "*.java"`
cd ./build ; jar -cvmf ../etc/manifest.stub ../libreadline-java.jar *
added manifest
adding: org/(in = 0) (out= 0)(stored 0%)
adding: org/gnu/(in = 0) (out= 0)(stored 0%)
adding: org/gnu/readline/(in = 0) (out= 0)(stored 0%)
adding: org/gnu/readline/Readline.class(in = 5156) (out= 2264)(deflated 56%)
adding: org/gnu/readline/ReadlineCompleter.class(in = 194) (out= 138)(deflated 28%)
adding: org/gnu/readline/ReadlineLibrary.class(in = 976) (out= 532)(deflated 45%)
adding: org/gnu/readline/ReadlineReader.class(in = 3034) (out= 1526)(deflated 49%)
adding: test/(in = 0) (out= 0)(stored 0%)
adding: test/ReadlineTest.class(in = 2235) (out= 1278)(deflated 42%)
adding: test/TestCompleter.class(in = 532) (out= 364)(deflated 31%)
cd src; make T_LIBS="JavaReadline" JAVAINCLUDE="/System/Library/Frameworks/JavaVM.framework/Home /include" \
JAVANATINC="/System/Library/Frameworks/JavaVM.framework/Home /include" native
cd native ; make T_LIBS="JavaReadline" JAVAINCLUDE="/System/Library/Frameworks/JavaVM.framework/Home /include" \
JAVANATINC="/System/Library/Frameworks/JavaVM.framework/Home /include" all
Makefile:100: *** missing separator. Stop.

Ryan said...

actually, it spit out:

cd src ; make JAVAC="javac" JC_FLAGS="" java
javac -d ../build `find . -name "*.java"`
cd ./build ; jar -cvmf ../etc/manifest.stub ../libreadline-java.jar *
added manifest
adding: org/(in = 0) (out= 0)(stored 0%)
adding: org/gnu/(in = 0) (out= 0)(stored 0%)
adding: org/gnu/readline/(in = 0) (out= 0)(stored 0%)
adding: org/gnu/readline/Readline.class(in = 5156) (out= 2264)(deflated 56%)
adding: org/gnu/readline/ReadlineCompleter.class(in = 194) (out= 138)(deflated 28%)
adding: org/gnu/readline/ReadlineLibrary.class(in = 976) (out= 532)(deflated 45%)
adding: org/gnu/readline/ReadlineReader.class(in = 3034) (out= 1526)(deflated 49%)
adding: test/(in = 0) (out= 0)(stored 0%)
adding: test/ReadlineTest.class(in = 2235) (out= 1278)(deflated 42%)
adding: test/TestCompleter.class(in = 532) (out= 364)(deflated 31%)
cd src; make T_LIBS="JavaReadline" JAVAINCLUDE="/System/Library/Frameworks/JavaVM.framework/Home /include" \
JAVANATINC="/System/Library/Frameworks/JavaVM.framework/Home /include" native
cd native ; make T_LIBS="JavaReadline" JAVAINCLUDE="/System/Library/Frameworks/JavaVM.framework/Home /include" \
JAVANATINC="/System/Library/Frameworks/JavaVM.framework/Home /include" all
Makefile:101: *** missing separator. Stop.
make[1]: *** [native] Error 2
make: *** [build-native] Error 2



* the last two lines were omitted in the previous post. *

Nathan Toone said...

I'm sorry - I don't have an intel-based machine available.

I'd try and look for anything that is out-of-whack on line 101 of the Makefile file. (it reported line 100 in your first post....)

The error: "Makefile:100: *** missing separator. Stop." is the one that tells you what file (Makefile) and line number (:100:) to look for the problem. Beyond that, I really can't help you without access to an Intel machine. (You want to buy me one ;) )

Nathan Toone said...

Actually, in looking at the steps, it appears the problem could be in how you edited your Makefile in src/native.

The line number you mention you have an error on corresponds with the line you edit in the third step there:

Make sure that the old line:
$(CC) -shared (OBJECTS) $(LIBPATH) $($(TG)_LIBS) -o $@

Reads:
$(CC) -bundle -flat_namespace $(OBJECTS) $(LIBPATH) $($(TG)_LIBS) -o $@

(all on one line for both of those)

Basically, replace "-shared" with "-bundle -flat_namespace" (no quotes)

Good luck.

Nathan Toone said...

I think I'll try and get them compiled as universal binaries....that will probably be the easiest - I can then just post them for download.

I hope to have it in the next couple of days.

Nathan Toone said...

OK - so I did the universal binaries...hopefully it's useful to someone.

Ryan said...

Thanks for the help Nathan. I think I got your recently released Universal Binaries working. There's a test that comes with the readline source (`java test.ReadlineTest`) that is giving me the appropriate results (a "linux>" prompt). I had to copy libJavaReadline.jnilib to /System/Library/Frameworks/JavaVM.framework/Libraries/ (on OS X 10.4 intel) and add libreadline-java.jar to my CLASSPATH.

I'm needing readline support for running jirb (the interactive ruby interpreter for jruby). when i start jirb i get the following message:

/jruby/jruby-0.9.1/lib/ruby/1.8/irb/completion.rb:187:in `method_missing':NoMethodError: undefined method `completion_append_character=' for Readline:Module

Anybody have any ideas?

I believe this is the same error I was getting before I installed the Universal Binaries for Readline. I'm stuck...

Nathan Toone said...

Did it not work if you put the two files into /Library/Java Extensions?

That's where I was able to get it working...You don't even need to modify your classpath or anything...that's *where* you are supposed to put your extensions.

As a general rule, it's a *bad idea* to modify anything in your /System directory...generally it's reserved for "Apple-only" use, and it has a lot different privileges associated with it. That could be part of the issue.

I'll try out jrib - I'm not familiar with it, but I'll see if I can get it going on my machine.

Nathan Toone said...

With the Universal binaries (on PPC) in /Library/Java Extensions, I am able to run jirb....I don't know what it does - but I get a "irb(main):001:0>" prompt... :)

Mike said...

Henplus runs on Leopard! I followed the steps above. I left everything as defined, even left /Developer/SDKs/MacOSX10.4u.sdk rather than changing it to /Developer/SDKs/MacOSX10.5.sdk.