NeuronRobotics / nrjavaserial

A Java Serial Port system. This is a fork of the RXTX project that uses in jar loading of the native code.
Other
345 stars 143 forks source link

Improved approach to building the native libraries #70

Closed mnlipp closed 8 years ago

mnlipp commented 8 years ago

This is just a proposal. Coming to the project from "outside" I find no clear approach how to build the native libraries. The existing Makefile is rather confusing -- besides, it looks rather like a shell script than a Makefile.

My approach is to use a Ubuntu (x86_64) system for building as many native libraries as possible. That's why I have created a new Makefile as Makefile.ubuntu64 (to indicate that it is supposed to be used on a Ubuntu x86_64 host). The host can (obviously) easily be used to build the Linux x86_64 and x86 libraries. Among all major Linux distributions, Ubuntu is (to my knowledge) the system that provides the best cross-compilation support. With the packages installed that are mentioned at the beginning of the Makefile.ubuntu64 the Ubuntu x86_64 host can be used to cross-compile the ARM libraries and the Windows libraries. (I've tested the resulting linux64, ARMv7HF, ARMv6HF, windows64 and windows32 libraries on my systems). Looking at the Ubuntu package list, it should also be possible to cross-compile for PPC. However, as I don't know anything about such systems, I haven't added it (what systems use a PowerPC? I only remember AIX).

This leaves FreeBSD (don't know why it needs special libraries), OS X (never owned a Mac, never will) and Android. I feel that cross compilation for Android should be easy to add, as cross-compilation is the "standard" way to create Android natives. And there is an Android cross-compilation toolchain in the Ubuntu repositories. But I currently have no time to look into that further.

MrDOS commented 8 years ago

Thanks for taking the time to dig into this. I've also put some amount of effort into this (#19). The problem with Linux binaries is that the resulting binary is inherently tied to the glibc version of the system under which compilation occurs. If you build on a newer distro, this leads to issues like #16 where the binary won't run on older distros. Given our backwards-compat concerns, we'd ideally build with support for glibc 2.5, which is the version used by CentOS 5 (the oldest supported release of a major distro). My most recent investigative path was the use of QEMU to target older distros.

That's not to say I don't appreciate the effort: I really do. Building natives is the hardest part of distributing to this project right now, and the difficulty level is quite a roadblock to making any changes to the native code. If you can figure out some way to target an older glibc with cross-compilation, I really want to hear about it: the virtual machine approach adds extra maintenance overhead, and it's still not easy for a passerby to use.

This crosstool-ng fork does a good job of cross-compiling OS X binaries on Linux, and Mingw-w64 does fine for Windows binaries, as you've probably discovered.

MrDOS commented 8 years ago

Oh, and

However, as I don't know anything about such systems, I haven't added it (what systems use a PowerPC? I only remember AIX).

The largest install base for PowerPC Linux is probably PS3s via the OtherOS functionality, followed by PowerPC-based Macs. And in a supercomputer sense, the IBM POWER processors are still current, with POWER8 having been released in 2014 and POWER9 due in 2017. How many of these systems are use-cases for NRJavaSerial remains in question, but the architecture is certainly not dead. (On the other hand, MIPS is probably a more useful target.)

mnlipp commented 8 years ago

Effectively, you want to compile against a specific (old) version of glibc instead of the one available on the system that you use for building. In a way, this is a cross-compilation. Therefore what you need is the old shared library which is passed to the linker (gcc -shared ...) instead of the system library. The shared object could go into the cross-compile-libs directory (where I already put the liblockdev.sos, that cannot be provided by Ubuntu packages for cross-compilation).

Of course, chances are high that the header files of the current glibc and the old shared object don't match. Therefore, you'll probably also need the old /usr/include-tree (actually only the relevant part of it) and put that first in the search path of the gcc invocation. Judging from the size of the ARM cross-compile include tree (/usr/arm-linux-gnueabi/include) this might add up to 44M to the project, but well, that's the "formal definition" of the API you're compiling against.

I haven't tested this, so I cannot be sure if it works, but if you want to avoid the maintenance effort for the virtual machine, it might be worth a try.

madhephaestus commented 8 years ago

I like your makefile MUCH better than the one i slapped together years ago. Until we resolve the glibc build procedure, would you mind re-submitting a PR with just the Makefile and Readme updates, but leaving out the binaries?

We can get that merged and perhaps us that as the build in the automated binary build.

mnlipp commented 8 years ago

Replaced by https://github.com/NeuronRobotics/nrjavaserial/pull/71 as requested.