File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Ant, Maven and Other Build Tools and the fly likes Linux vs. Windows jar file - cannot find main class Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » Ant, Maven and Other Build Tools
Bookmark "Linux vs. Windows jar file - cannot find main class" Watch "Linux vs. Windows jar file - cannot find main class" New topic
Author

Linux vs. Windows jar file - cannot find main class

Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
I have an ant build file that works for Windows and Linux. By that I mean it successfully builds the jar file on either Windows or Linux and the results appear to be identical. However, either resulting jar file works on Windows but fails on Linux with the "Could not find the main class" error. Why the difference and how do I fix that? TIA.
Jan Cumps
Bartender

Joined: Dec 20, 2006
Posts: 2499
    
    8

Do you use the correct class path on both platforms when executing?


OCUP UML fundamental and ITIL foundation
youtube channel
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
I have to confess that I don't yet really understand class paths in ANT. Obviously I thought I had the correct one for both. The compiles on each are done at the same place in the same directory tree so why would the class paths be different in the Jar file? In any case I have no clue what I would need to change or where.
Tina Smith
Ranch Hand

Joined: Jul 21, 2011
Posts: 171
    
    5

What's the command you're using to run the jar file?

Linux (ubuntu anyways) and Windows use a different character for classpath separators, ";" in windows and ":" in linux.

See also:
http://stackoverflow.com/questions/4528438/classpath-does-not-work-under-linux


Everything is theoretically impossible, until it is done. ~Robert A. Heinlein
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Thanks for the reply. I looked at the reference you gave and I don't think that applies. I am using relative paths and compiling on both platforms from the same place in the tree. I do account for some OS differences in the build file but it is not clear to me if any of that applies in this case. Even if it did, would that not then make the jar file platform dependent? Here is my working XML file:
Tina Smith
Ranch Hand

Joined: Jul 21, 2011
Posts: 171
    
    5

If you can run the jar file built in Linux on Windows, it's a problem with how you're running the jar file rather than how you're building it. That's where the references to classpath come in.

What commands are you using (in both windows and linux) to start the program's execution?
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Ah, that makes some sense then. I run it on Windows via Eclipse's ANT, which perhaps hides too much from me and may not be running the way I think. On Linux I use 'ant -f makejar.xml'.
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
I'm afraid I have made absolutely no progress with this problem. Given the previously posted build file, can someone give me something more explicit to fix this? TIA.
Tina Smith
Ranch Hand

Joined: Jul 21, 2011
Posts: 171
    
    5

You're using eclipse's ant to build the jar then eclipse to run your program from the built files. Can you run the program on windows/linux as per the following command, run in the same directory as the jar file:

java -jar KCBSEvents.jar

or

(on windows)
java -cp .;KCBSEvents.jar KCBSEvents/KCBSEvents

(on linux)
java -cp .:KCBSEvents.jar KCBSEvents/KCBSEvents

Is it the KCBSEvents class that cannot be found, or some other class?
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21

Regardless of the OS used, the process is the same.

If you issue the command


then the Java runtime will open xzy.jar, look for the file META-INF/manifest.mf and scan for a "Main-Class:" specification. The value of this statement MUST be the fully-qualified classname (including package) of a class containing a method with the signature of "public static void main(String[] args)". This method will then be executed, running the app in the jar.

The "-classpath" and "-jar" options are mutually exclusive. The "-jar" option assumes that the classpath is the jar and only the jar. The only exception is for cases where the application itself modifies the classpath internally. A good example of that are apps like SchemaSpy that need an external JDBC driver in order to work.


Customer surveys are for companies who didn't pay proper attention to begin with.
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Thanks for the reply but I guess I am not understanding the other replies. If the process is the same regardless of the OS (which is what I really expected), why does the previously posted build file produce a jar file that works on Windows (regardless of which OS builds it) but does not work on Linux and gets the cannot find main error? That was why I started this thread in the first place.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21

A properly-formed, properly-executed jar won't be deependent on the OS.

Unzip the jar and check the following:

1. There should be a META-INF/manifest.mf file. It should contain a line that starts with "Main-Class: ". I think that that line can end with either MS-DOS/Windows (CRLF) or Unix/Linux (NL) characters, but you might want to check Oracle's docs on jar manifests.

2. The main class that was referenced on the Main-Class manifest directive (and make sure it's properly capitalized!) should exist as a class file in the jar. Its location MUST be as defined in the package/classname definition. That is, a "com.mousetech.testapp1.TestApp" directive must have a corresponding file named "com/mousetech/testapp1/TestApp.class". It must be in EXACTLY that directory structure, and the directory names are CASE SENSITIVE even under Windows. Doubly so for Linux. Note that the Main-Class is the classname, not the filename, so no ".class" on the manifest.

Also, when referring to files in Java, the recommended notation is Unix-style, even when referring to Windows file paths. In other words, use the forward-slash ("/") file separator, not the DOS backslash. Java can deal with either notation, but backslashes have an alternative meaning that can cause pain.
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18563
    
    8

Case-sensitivity is a definite possibility. If some code asks Windows to find a file named "Something.class", it will happily return a file named "something.class" without comment. Whereas UNIX-like systems won't. Hence why some code might run on Windows but fail on the UNIX-like system. (I have had that happen to me.)
Peter Johnson
author
Bartender

Joined: May 14, 2008
Posts: 5827
    
    7

Try this. Build the JAR on both Windows an Linux. Then use "jar -tf KCBSEvents.jar" to dump the JAR contents, make sure they are the same.

Does the bin directory on both systems contain the exact same set of files? (Why isn't this build script also compiling the Java sources? Right now it is relying on an external process to have compiled them, which is a sure way of screwing things up!)


JBoss In Action
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Thanks for all the replies folks. You gave me quite a list of things to do.

Tina) In the case of the java -jar command, it works on Windows but not Linux (cannot find main error). However, the java -cp command works on both. That must be a good clue.

Tim) The manifest files are identical including case. Not sure about the line end character (that would make it platform dependent would it not?) but between you and Tina we may be homing in on the problem.

Peter) The result of dumping the jar files were identical. The compiling is done by Eclipse during my testing. I was not aware that not compiling as part of the build would matter. Does not Eclipse use the same javac as ANT? In any case, if you think that is worth the effort (could this be related to Tina's discovery?), I'll add that step to my build file.
Peter Johnson
author
Bartender

Joined: May 14, 2008
Posts: 5827
    
    7

Not sure about the line end character

How do you transfer the files from one system to another? If you use FTP in text mode, you will definitely mess up the JAR file.

The compiling is done by Eclipse during my testing.

That explains it. I'm used to having an Ant script that does everything. I rarely use Eclipse to compile anything - I use only as a glorified text editor.

Please provide the following information:

1) The exact command used to run the application on each platform (the one that caused you to post the original question).

2) The result of running "jar -tf" on each JAR file (one from each platform).

3) The "import" directives in KCBSEvents.KCBSEvents.

4) The full class statement of KCBSEvents.KCBSEvents (the classes it extends and the interfaces it implements).

5) The locations on each system of the JAR files containing the classes referenced in the import directives. (It might not be that the main class cannot be found, but rather than the classes referenced are not available.)
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
First, every thing is done from the same directory. The physical space resides on a Linux share and is mapped as a network drive on Windows.

1) From Windows I run makejar.xml from within Eclipse (I did try running it from command line using ant but it did not seem to matter). On Linux I use 'ant -f makejar.xml'

2) Windows:

META-INF/
META-INF/MANIFEST.MF
KCBSEvents/
KCBSEvents/resource/
KCBSEvents/Base64Coder.class
KCBSEvents/DoSearch$1.class
KCBSEvents/DoSearch$2.class
KCBSEvents/DoSearch.class
KCBSEvents/EventClass.class
KCBSEvents/EventStub.class
KCBSEvents/EventTableModel.class
KCBSEvents/FormClass.class
KCBSEvents/GetPage.class
KCBSEvents/Helpers.class
KCBSEvents/KCBSEvents$1.class
KCBSEvents/KCBSEvents.class
KCBSEvents/KCBSLogo.jpg
KCBSEvents/KeyClass.class
KCBSEvents/KeyGenerator.class
KCBSEvents/MenuBar.class
KCBSEvents/MessageScreen$1.class
KCBSEvents/MessageScreen$2.class
KCBSEvents/MessageScreen$3.class
KCBSEvents/MessageScreen.class
KCBSEvents/MouseClicks.class
KCBSEvents/ParseKCBS.class
KCBSEvents/Registration.class
KCBSEvents/RegistrationScreen$1.class
KCBSEvents/RegistrationScreen$2.class
KCBSEvents/RegistrationScreen$3.class
KCBSEvents/RegistrationScreen$4.class
KCBSEvents/RegistrationScreen$5.class
KCBSEvents/RegistrationScreen.class
KCBSEvents/SavedEvents.class
KCBSEvents/SearchFrame$1.class
KCBSEvents/SearchFrame$2$1.class
KCBSEvents/SearchFrame$2.class
KCBSEvents/SearchFrame$3.class
KCBSEvents/SearchFrame$4.class
KCBSEvents/SearchFrame.class
KCBSEvents/SplashScreen$1.class
KCBSEvents/SplashScreen$2.class
KCBSEvents/SplashScreen.class
KCBSEvents/TableCellRenderer.class
KCBSEvents/VERSION.class
KCBSEvents/resource/build.properties


Linux

META-INF/
META-INF/MANIFEST.MF
KCBSEvents/
KCBSEvents/resource/
KCBSEvents/Base64Coder.class
KCBSEvents/DoSearch$1.class
KCBSEvents/DoSearch$2.class
KCBSEvents/DoSearch.class
KCBSEvents/EventClass.class
KCBSEvents/EventStub.class
KCBSEvents/EventTableModel.class
KCBSEvents/FormClass.class
KCBSEvents/GetPage.class
KCBSEvents/Helpers.class
KCBSEvents/KCBSEvents$1.class
KCBSEvents/KCBSEvents.class
KCBSEvents/KCBSLogo.jpg
KCBSEvents/KeyClass.class
KCBSEvents/KeyGenerator.class
KCBSEvents/MenuBar.class
KCBSEvents/MessageScreen$1.class
KCBSEvents/MessageScreen$2.class
KCBSEvents/MessageScreen$3.class
KCBSEvents/MessageScreen.class
KCBSEvents/MouseClicks.class
KCBSEvents/ParseKCBS.class
KCBSEvents/Registration.class
KCBSEvents/RegistrationScreen$1.class
KCBSEvents/RegistrationScreen$2.class
KCBSEvents/RegistrationScreen$3.class
KCBSEvents/RegistrationScreen$4.class
KCBSEvents/RegistrationScreen$5.class
KCBSEvents/RegistrationScreen.class
KCBSEvents/SavedEvents.class
KCBSEvents/SearchFrame$1.class
KCBSEvents/SearchFrame$2$1.class
KCBSEvents/SearchFrame$2.class
KCBSEvents/SearchFrame$3.class
KCBSEvents/SearchFrame$4.class
KCBSEvents/SearchFrame.class
KCBSEvents/SplashScreen$1.class
KCBSEvents/SplashScreen$2.class
KCBSEvents/SplashScreen.class
KCBSEvents/TableCellRenderer.class
KCBSEvents/VERSION.class
KCBSEvents/resource/build.properties


3 & 4)

It occurred to me, while building this post, that this code has gone through a lot of changes (mostly moving all the work to other classes) as I learned java. I question, at this point, why I need 'extends JFrame' any more since there are no swing related methods other than invokeLater and showWindow. However, I also don't see why that would matter to this problem.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21

Just to round out the roster, show us the actual manifest.mf file itself.

You shouldn't need to build under both Windows and Linux unless you want to. One build under either OS should result in a jar capable of running under both OS's.

The reason why I suggested checking the official specs on the manifest file is that because if there's a specific line termination requirement, it would be the Unix one, even under windows. But I'm pretty sure that both CR-LF and NL (LF) are OK here. Since the jar is usually compressed, the EOL character(s) would probably not get mangled specifically if the file was transmitted in text mode, but the classes would be chewed up pretty badly on a semi-random basis. Note that the default for Windows FTP servers is text mode and the default for most of the rest of the world is binary (Image) mode. When in doubt, manually select the mode before uploading. Network file shares don't carry this caveat.
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Thanks again. Here is the manifest:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.6.0 (Sun Microsystems Inc.)
Main-Class: KCBSEvents.KCBSEvents

I do need to generate the jar file on both. I will have an automated web access method for generating the jar file via Apache on a Linux server. I still need to be able to manually create them on occasion which I do from Windows.

However, as I said the real issue is that regardless of which OS I use to produce the jar, the result works on Windows but not on Linux and that is where I'm hung up at the moment.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21

I don't think that this is it, but a package name starting with an upper-case character is a violation of the package naming conventions. Classes should begin uppercase, packages and instances should have lower-case beginnings. As a rule, I wouldn't use any uppercase at all in a package name component at any level.
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
The reason I chose uppercase is because it is an acronym and because it was before I learned the conventions. I can change it if necessary but I gather you really don't think it is an issue.
Peter Johnson
author
Bartender

Joined: May 14, 2008
Posts: 5827
    
    7

Which version of Java are you using on Linux? Run both "java -version" and "$JAVA_HOME/bin/java -version".

Also, remove "extends JFrame" since you no longer need that. Like I mentioned earlier, it could be additional classes that are required by KCBSEvents that are the cause of this issue, and not KCBSEvents itself.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21

Well, there are all sorts of minor irregularities here, as we've mentioned, but if you've listed any actual deal-breakers, I've missed them

Since running the command with the -classpath option works, but the same attempt using the -jar option does not, that would tend to indicate that there's something wrong with the manifest or that the manifest isn't being found. I RTFM'ed, and it's META-INF/MANIFEST.MF (all upper-case). Hopefully the sample manifest you displayed was what came out of the command "jar -xf xyz.jar META-INF/MANIFEST.MF" and not simply what "should" be in MANIFEST.MF

It really, truly isn't supposed to be this hard, honest! We've reached the point where if it was happening to me, I'd try running it under a debugger, intercept the ClassNotFoundException and nose around the stack until I found out what on Earth was going on.

Wait a minute. It's not a problem that your Main class is a Swing extension, BUT your main method has an invalid form. DON'T put "throws" on a "public static void main(String[])". There's no place to throw the exception to! The JVM that calls main() doesn't count. So that may cause the main() method not to be found, disqualifying its containing class as a main-class. If main receives checked exceptions, it should catch them and dump a stacktrace or something.

While this behaviour shouldn't vary with the OS, the actual matchup is a little "iffy" since the signatures for both versions of main() - with and without throws clauses - are the same, but most method lookup functions won't accept variances in the throws clauses.

Also, Tina's command-line examples using the -cp are wrong. I presume you were aware of that. The proper form is "java -cp xyz.jar KCBSEvents.KCBSEvents". As is the case of the manifest directive, the classname is used, not the file pathname.
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Thanks again for the help. I cleaned up the two issues (throws, JFrame) but still no progress. The manifest I posted is indeed what is in the jar file however, it is exactly what is in the ant build file so the contents are as expected. What other "minor irregularities" do I need to clean up, if any? As for debugging, I guess that is where I need to go next. Is Oracle's jdb sufficient or do you recommend something else for Linux?
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21

The actual debugger is part of the JVM. All the IDE supplies is a pretty interface. So, while I'm most comfortable with the Eclipse debugger, the command-line jdb can do the job. You just have to type commands instead of clicking on things you want to look at.
Peter Johnson
author
Bartender

Joined: May 14, 2008
Posts: 5827
    
    7

Now that you have made several changes, please post the full output of running the app on Linux (when it fails), along with the command used to run it. Also, could you post the JAR file that is in error?
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
Here is the Linux command and output:

java KCBSEvents.jar

Exception in thread "main" java.lang.NoClassDefFoundError: KCBSEvents/jar
Caused by: java.lang.ClassNotFoundException: KCBSEvents.jar
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
Could not find the main class: KCBSEvents.jar. Program will exit.

Here is the main class:

I see the error refers to KCBSEvents/jar. Shouldn't that be KCBSEvents/KCBSEvents per the manifest?
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16051
    
  21


I see the error refers to KCBSEvents/jar. Shouldn't that be KCBSEvents/KCBSEvents per the manifest?


No. You gave an unqualified parameter name on the command line. Since it wasn't a keyword, it was interpreted as the first (only) positional parameter, which for the "java" program is always the fully-qualified name of the main class. The JVM then searched the classpath for a class named "KCBSEvents.jar", which should have been located at KCBSEvents/jar.class within the classpath.

Compounding the issue would be the fact that the only classpath that exists is whatever classpath you've set in the environment, since the current directory is not implicitly part of the classpath for security reasons.

In other words, the correct command is:
Dennis Putnam
Ranch Hand

Joined: Feb 03, 2012
Posts: 217
So you are saying this entire thread was because I used the wrong command under Unix? Gaahhhh!
Peter Johnson
author
Bartender

Joined: May 14, 2008
Posts: 5827
    
    7

Well, how did you run under Windows? Don't tell me you used different commands on each platform?

Also, do you have the CLASSPATH env var set? If you had it set on Windows but not Linux, or of the settings were different, or you were running from different directories, that could cause the difference. For example, if you set CLASSPATH to "bin" and you were in the project base directory, then the command you gave would work.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Linux vs. Windows jar file - cannot find main class