First some reference:
1st Link
2nd link
The first article 1st Link mentions about compiling the Java files directly into JAR files and avoiding one step in the build process. Does anyone know this?
-Vadiraj
As you linked to my blog post I thought it was only fair to give you an update.
Compiling directly to a Jar is actually fairly simple to do. Basically you extend
javax.tools.ForwardingJavaFileObject
Then override openOutputStream method and direct it to your Jar. As the Java Compiler is highly concurrent but writing to a jar file is highly sequential I'd recommend that you buffer to byte arrays and then have a background thread that writes the byte arrays as they arrive.
I do exactly this is my experimental build tool JCompilo https://code.google.com/p/jcompilo/
This tool is completely undocumented but crazy fast. Currently it's about 20-80% faster than any other Java build tool and about 10x faster than the Scala compiler for the same code.
As the author is talking about extending the compiler itself, it is possible that he has knowledge of the built-in capabilities of the compiler (that is what the compiler is capable of, maybe with a little encouragement by tweaking the code).
Right now I’m investigating extending the Java 6 compiler to remove the unneeded file exists checks and possible jaring the class files directly in the compiler. [emphasis mine]
That capability, however, is certainly not supported officially (no documentation exist about it on the javac webpage).
At best, the feature is compiler dependent; possibly requiring modification of the compiler's source code.
Related
I have a question which I'm pretty confused from.
I am aware of the differences between Java Runtime Enviroment and Java Developement Kit.
I'm writing a program that uses the ToolProvider.getSystemJavaCompiler() method to compile java code from within the code.
Now, I've been answered that I can't compile code from client side if my client doesn't have JDK installed. My main question is, how can I do that? I don't want my clients having to install JDK on their computer just to run my program.
Thanks in advance!
You need to compile it on your system, and distribute the class file of corresponding java source file to anyone.
That class file doesn't require JDK but JRE must be installed on that system to run the class file.
If you want to compile code, you need a compiler, so if the user can't be expected to have the compiler you need, you'll simply have to bundle it.
I really can't say I know how to bundle the standard javac compiler, though it's probably possible, strictly speaking, to find the Jar file that contains it and bundle that along with your code. No idea how robust such a solution would be, though.
But depending on your needs, you may not need the standard javac. There are tons of byte-code generation libraries out there, with more or less high-level functionality. I wouldn't really want to recommend anything that I have no personal experience with, but examples include Byte Buddy or ASM. You could probably use ABCL too.
Eclipse's compiler is worth a look as well.
There is also an so question here.
So there really is no way to do what it is you are wanting to do unless you bundle the compiler itself with you application, or unless you find a library that has all of the Java compiler code in it already so it doesn't have to use the JDK compiler, you will not get what you want, and what you want is the ability to turn a String containing source code into a Java class.
I do not understand what you wish to accomplish, but the BEST option I can give you is asm. If you are up for the task, you can manually write new classes at runtime without the presence of the JDK compiler. HOWEVER, this does not involve you using a String full of source code and turning it into a Class object. This is you working at the low level with the Java bytecode for the most part.
This tutorial can get you started:
https://www.javaworld.com/article/2071777/design-patterns/add-dynamic-java-code-to-your-application.html
And here is the Java documentation for class files. You can use this to expand on what you learned from the first link:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
That is the only instance creating classes on the fly that I can give you. That being said, you could try writing your own Java compiler that can turn source code into classes without ever getting the Java compiler, but at that point you are literally recreating the Java compiler yourself, and I assure you that is no easy feat for one person.
There has been some buzz about a tool called sjavac on the OpenJDK mailing lists. Also, there are two related JEPs: JEP 139: Enhance javac to Improve Build Speed and JEP 199: Smart Java Compilation, Phase Two.
My questions are:
What exactly is the sjavac tool?
Who is it intended for?
How do I use it?
Disclaimer: Self answered question. Just wanted to bring the knowledge of this tool to the StackOverflow community and to create a reference to future sjavac FAQ.
What exactly is the sjavac tool?
The sjavac tool is an (allegedly smart) wrapper around javac, developed at Oracle and intended to provide the following features:
incremental compiles - recompile only what's necessary
parallel compilation - utilize more than one core during compilation
keep compiler in a hot VM - reuse a JIT'ed javac instance for consecutive invocations
When recompiling a set of source files, javac looks at the timestamps of the .java and .class files to determine what to keep and what to recompile. This is incredibly crude and can be devastating for large code bases. In addition to the timestamps sjavac inspects the public API of the dependencies to judge which files need to be recompiled.
Sjavac also attempts to split up the compilation into multiple invocations of javac. In other words, it brings a high level of parallelism to the build process.
Finally, the sjavac tool is split in a client part and a server part which allows you to leave sjavac running in the background, JIT'ed and ready for use in consecutive calls.
Who is it intended for?
People who are working on large projects and frequently recompiles the code base during development are encouraged to try out sjavac. (Be aware however that the tool is currently under development and there are still open issues.)
How do I use it?
The tool is not yet shipped with the OpenJDK, so you'll have to get it from the OpenJDK jdk9/dev repository. Also, there is no launcher in place yet, so you invoke it with java com.sun.tools.sjavac.Main.
Being new to Java, I am not able to understand the complete build process from source code to hardware specific binaries. Basically I am using Eclipse for java and would like to know what all conversions takes place from source code(.java) to binary, what all files are linked using some linker, preprocessor etc etc.
Shall appreciate if you can point me to some link giving detail of complete build process for java. I have already searched this forum but did not get detail info.
Thanks
Edited:
So to be more precise I am looking for java equivalent of following build process in C:
I googled a lot but no gain! A figure like the following is not a must(though preferred), but if you can write 'n' sequential/parallel steps involved in complete Java build process, that will be really appreciated. Though much of the information provided by #Tom Anderson is very useful to me.
The first thing to appreciate is that your question contains a mistaken assumption. You ask about "the complete build process from source code to hardware specific binaries" - but the normal Java build process never produces architecture-specific binaries. It gets as far as architecture-independent bytecode, then stops. It's certainly true that in most cases, that bytecode will be translated into native code to be executed, but that step happens at runtime, inside the JVM, entirely in memory, and does not involve the production of binary files - it is not part of the build process.
There are exceptions to this - compilers such as GCJ can produce native binaries, but that is rarely done.
So, the only substantial step that occurs as part of a build process is compilation. The compiler reads in source code, does the usual parsing and resolution steps, and emits bytecode. That process is not in any way specified; as is usual, the language specification defines what the elements of the language are, and what they mean, but not how to compile them. What is specified in the format of the output: the bytecode is packaged in the form of class files, one per class, which in turn may be grouped together in jar files for ease of distribution.
When the class files come to be executed, there are then further steps needed before execution is possible. These are quite well-specified in the chapter on loading, linking, and initializing in the JVM specification. But, as i said, these are not really part of the build process.
There are a few other steps that may occur in a build process, usually prior to compilation: dependencies might be resolved and downloaded, resources might be copied and converted between character sets, and code might be generated. But none of this is standard, it's all stuff that's added on to the core process of compilation by various build tools.
There are some cool articles you can checkout if you want to know what's going on "behind the scenes".
http://www.codeproject.com/Articles/30422/How-the-Java-Virtual-Machine-JVM-Works
This is one of them, it has a good explanation on how all the parts interact to run your code.
The main idea is that the bytecode is created from your Java files to run in a Virtual Machine, making your Java code (more or less...) independent of the OS and platform you're running it on.
The JVM, specific to that environment, is then responsible for translating that bytecode into actual instructions for the specific architecture you're running your code on.
This is the basis of the "Write once, run everywhere" mantra that Java has. Although the mantra doesn't always hold... it's still true in general.
I'm trying to limit changes from a jar file. I introduced a fix on the code, a very small fix in a single file. Javac compiler generates the new .class file and I plan to replace ONLY this single file in the jar (we had problems with the build and are unsure if the current build matches the production build).
I'm a C++ pro, but java... not so much. I wouldn't dare to do this in C++ as optimizers inline a lot of stuff from object files and static libs. I'm under the impression I can do this with no great consequences in java.
Any advice?
I usually hot deploy files on server, that creates no problem in JAVA. You can do it as long as your compiler version is same as the other files. It would not be a problem.
The Java Language Specification defines binary compatibility between class files. In general, class files tend to be much more compatible than they would be in C, so you'll probably be ok. However, there are a few gotchas, such as static final fields (constants) which are inlined by the compiler.
In any case, the situation in which you are not sure what code code you have running in production, I would consider to be very dangerous, and try to fix as soon as possible.
First, I have no experience doing this. But like the beginning of any good program, I have problem that I need to fix, so I'm willing to learn.
So many of you are probably already familiar with pdftk, the handy utility for handling various pdf-related tasks. So far as I can tell, most of these features are available in much newer, lighter libraries/extensions, except the one I need (and probably the only reason it still exists): merging form data files (fdf and xfdf) with a form PDF and getting a new file as the output.
The problem is that my server doesn't have gcj, which is fundamental to build/compile pdftk. I don't know if it's because I'm on Solaris or if it's for some other sysadmin-level reason, but I'm not getting gcj anytime soon. And there are no pre-compiled binaries for Solaris as far as I can find.
So I'm thinking that the MAKE file and C code can be rewritten to import the Java library (very ancient version of itext) directly, via javac.
But I'm not sure where to really start. All I know is:
I want a binary when I'm done, so that there won't be a need for a Java VM on every use.
The current app uses GCJ.
So my first thought was "Oh this is easy, I can probably just call the classes with some other C-based method", but instead of finding a simple method for doing this, I'm finding tons of lengthy posts on the various angles that this can be approached, etc.
Then I found a page on Sun's site on how to call other languages (like C) in a Java class. But the problems with that approach are:
I'd have to write a wrapper for the wrapper
I'd probably be better off skipping that part and writing the whole thing in Java
I ain't ready for that just yet if I can just import the classes with what is already there
I'm not clear on if I can compile and get a binary at the end or if I'm trapped in Java being needed every time.
Again, I apologize for my ignorance. I just need some advice and examples of how one would replace GCJ dependent C code with something that works directly with Java.
And of course if I'm asking one of those "if we could do that, we'd be rich already" type questions, let me know.
I'm not sure what you are looking for exactly, so I provided several answers.
If you have java code that needs to run, you must:
Run it in a jvm. You can start that vm within your own custom c-code, but it is still using a jvm
Rewrite it in another language.
Compile with an ahead-of-time compiler (eg gcj)
Incidentally, you could compile a copy of gcj in your home folder and use that. I believe the magic switch is --enable-languages=java,c (see: here for more)
If you have c-code you want to call from java, you have four options:
Java Native Interface (JNI). It seems you found this
Java Native Access (JNA). This is slower than JNI, but requires less coding and no wrapper c-code. It does require a jar and a library
Create a CLI utility and use Runtime.Exec(...) to call it.
Use some sort of Inter Process Communication to have the Java code ask the c-code to perform the operation and return the result.
Additional platform dependent options
Use JACOB (win32 only: com access)
I am not sure if I understand what you are looking for.
If you are looking to incorporate the C code into Java to make a native binary without the gcj, I think you are out of luck. You can include the C in Java, but it would be a primarily Java program meaning you would need the JVM on each run. Is there anything stopping you from compiling the gcj yourself?