hhrzc
hhrzc

Reputation: 2050

jar from Main.class creation: no main manifest attribute, in jar

I need to create a jar file and not use maven or gradle packages.

First of all - I used all options that I saw in StackOverflow, so please, do not mark this question as duplicated if you are not sure about the solution that you will find - more of them I have tried.

Project structure:

\src
  ---\Main.java
  ---\A.java
  ---\B.java

Steps:

1. Compiling:

javac \src\*.java

\src
  ---\Main.class
  ---\A.class
  ---\B.class

2. MANIFEST file created:

Manifest-Version: 1.0
Main-Class: src.Main

3. Compiling to the jar:

jar cfm test.jar MANIFEST.MF src/

4. Launching:

java -jar test.jar

result:

no main manifest attribute, in test.jar

Also I was trying following:

jar cvfe myjar.jar src.Main src\*.class

and many other options - the same result


How to correctly create a jar file natively?

Upvotes: 0

Views: 818

Answers (3)

user16320675
user16320675

Reputation: 135

The Name-Value lines of the Manifest file must be terminated by a newline (CR LF, CR or LF) according the JAR Specification:

section:           *header +newline
nonempty-section:  +header +newline
newline:           CR LF | LF | CR (not followed by LF)
header:            name : value

Since the manifest file contains Main-Class: src.Main but it is not being recognized ("no main manifest attribute..."), the newline is probably missing after that line - the last line.
Some editors do not add a newline at the end of the file.

To avoid that problem always include an empty line at the very end of the Manifest file.

very old problem, I would expect the jar tool to correct that, or at least warns about it

Upvotes: 0

OneCricketeer
OneCricketeer

Reputation: 191743

$ java -version
java version "17.0.3" 2022-04-19 LTS
Java(TM) SE Runtime Environment (build 17.0.3+8-LTS-111)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.3+8-LTS-111, mixed mode, sharing)

$ javac -version
javac 17.0.3

Use a Makefile

JAVAC=javac
MAIN_CLASS=Main
APP_NAME=app
sources = $(wildcard src/*.java)
classes = $(sources:.java=.class)


all: program

program: $(classes)

clean:
    @rm -rf out/
    @rm *.jar

%.class: %.java
    @$(JAVAC) -d out $<

jar: $(classes)
    @jar -v --create --file $(APP_NAME).jar --main-class $(MAIN_CLASS) -C out/ .

exec: jar
    java -cp .:out -jar $(APP_NAME).jar

.PHONY: all program clean jar

Folder structure

├── Makefile
└── src
    └── Main.java
$ make clean exec
added manifest
adding: Main.class(in = 413) (out= 288)(deflated 30%)
java -cp .:out -jar app.jar
Hello world

Upvotes: 0

life888888
life888888

Reputation: 2999

Project structure

DemoApp
├── MANIFEST.MF
└── src
    ├── A.java
    ├── B.java
    └── Main.java

MANIFEST file

Manifest-Version: 1.0
Main-Class: Main

Main.java

No package

import java.util.Calendar;

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");
        System.out.println(new A().hello("WORLD"));
        System.out.println(new B().echo(Calendar.getInstance().getTime().toString()));
    }
}

Steps

1. Compiling:

javac src/*.java -d out

result

DemoApp
└── out
    ├── A.class
    ├── B.class
    └── Main.class

2. Copy MANIFEST.MF to out

cp MANIFEST.MF out/

result

DemoApp
└── out
    ├── A.class
    ├── B.class
    ├── Main.class
    └── MANIFEST.MF

3. Packing jar

cd out
jar cfm ../app.jar MANIFEST.MF *.class
cd ..

final result

DemoApp
├── app.jar
├── MANIFEST.MF
├── out
│   ├── A.class
│   ├── B.class
│   ├── Main.class
│   └── MANIFEST.MF
└── src
    ├── A.java
    ├── B.java
    └── Main.java

4. Launching:

java -jar app.jar

Jar file structure

app.jar
├── A.class
├── B.class
├── Main.class
└── META-INF
    └── MANIFEST.MF

Project structure - No MANIFEST.MF

DemoApp
└── src
    ├── A.java
    ├── B.java
    └── Main.java

Steps

Compile .java

javac src/*.java -d out

Result

DemoApp
├── out
│   ├── A.class
│   ├── B.class
│   └── Main.class
└── src
    ├── A.java
    ├── B.java
    └── Main.java

Packing jar

jar cfe app.jar Main -C out /

Result

DemoApp
├── app.jar
├── out
│   ├── A.class
│   ├── B.class
│   └── Main.class
└── src
    ├── A.java
    ├── B.java
    └── Main.java

Launching:

java -jar app.jar

Upvotes: 1

Related Questions