1. 程式人生 > >利用原始的javac手寫編譯指令碼編譯整個Java專案

利用原始的javac手寫編譯指令碼編譯整個Java專案

如何編譯一個無包結構的單個java檔案,無依賴jar包,除了JDK;以及執行該檔案?

在任何目錄(/home/vc/javacDemo/one)下新建NoPackageClass.java檔案

public class NoPackageClass {
    public static void main(String[] args) {
        System.out.println("This is no package class!");
        System.out.println("java.io.tmpdir property: "+System.getProperty("java.io.tmpdir"
)); } }

進入改目錄下執行

javac -encoding UTF-8 ./NoPackageClass.java 編譯原始檔,只指定了原始檔原始碼格式為UTF-8

執行:java NoPackageClass,這裡執行class檔案並不需要加class檔案字尾,只要java 命令後跟具有main函式的class檔名即可。

輸出:

This is no package class!
java.io.tmpdir property: /tmp

如何編譯一個有包結構的java檔案, 無依賴jar包,除了JDK; 以及如何執行該檔案

在目錄/home/vc/javacDemo/two

下建立下面檔案,原始檔並沒有根據package 放置在根據package劃分的目錄中。

package org.vincent;

public class PackageClass {
    public static void main(String[] args) {
        System.out.println("This is package class!");
    }
}

這個時候因為原始檔已經有package 進行管理了,那麼需要新增一個引數-d, 用於指定編譯後的class 檔案存放的基目錄,然後javac會根據包結構再生成相應的資料夾 。

當我們在 /home/vc/javacDemo/two

java原始碼所在目錄下執行javac命令編譯原始碼時候,-d ./表示以原始碼所在目錄為class檔案的根目錄。javac -encoding UTF-8 -d ./ PackageClass.java 最後編譯的class 檔案所在目錄為:/home/vc/javacDemo/two/org/vincent class檔案根目錄 + org/vincent (這個也是包結構)

執行 只能在class 檔案根目錄下執行,就是我們maven專案熟知的target目錄

同時需要執行main方法類所在的全路徑名稱:java org.vincent.PackageClass
輸出:This is package class!

批量編譯大量java檔案

新增 PackageClassTwo.java 檔案

package org.vincent;

public class PackageClassTwo{
    public static void main(String[] args) {
        System.out.println("This is package class!");
    }
}

相當於現在在/home/vc/javacDemo/two 目錄下有兩個原始檔 PackageClassTwo.java , PackageClass.java ,在當前源目錄下執行javac命令編譯檔案,然後在當前目錄下的org/vincent子目錄有兩個編譯好的class檔案

 javac -d ./ -encoding UTF-8 ./*.java

執行:java org.vincent.PackageClass, java org.vincent.PackageClassTwo檔案兩個命令都可以進行執行輸出:This is package class!

修改 PackageClass.java檔案引用PackageClassTwo類

package org.vincent;

public class PackageClass {
    public static void main(String[] args) {
        System.out.println("This is package class!");
        PackageClassTwo two=new PackageClassTwo();
        System.out.println(two.toString());
    }
}

使用 下面javac命令編譯

 javac -d ./ -encoding UTF-8 ./*.java

java命令執行執行:java org.vincent.PackageClass, java org.vincent.PackageClassTwo

檔案兩個命令都可以進行執行輸出:
java org.vincent.PackageClass 命令輸出:

This is package class!
org.vincent.PackageClassTwo@15db9742

java org.vincent.PackageClassTwo 命令輸出:

This is package class!

說明PackageClass 類可以引用到 PackageClassTwo類。

這個才是比較正常的專案,通過手動編寫指令碼使用javac編譯一個完整的java專案

不用maven這些構建工具,直接把原始碼上傳到Linux伺服器手寫指令碼手動編譯成一個可執行jar程式。

這是一個有package 管理,有依賴的簡單的java程式。專案根目錄下有這些東西

  • 專案根目錄
    • src 原始碼根目錄,package目錄隨便
    • lib 依賴包跟目錄,lib 目錄下一般是直接放jar檔案沒有在有目錄,這個目錄和MANIFEST.MF中Class-Path引數有關係
    • MANIFEST.MF 檔案: 定義了入口main方法所在類,以及依賴包的位置


      # 重點是編譯指令碼
#! /bin/bash
# 此處應該是專案資料夾所在目錄
cur_dir=$(pwd)
echo $cur_dir


function compile(){
        # 記錄專案的根目錄所在路徑
        project_name=javacDemo
        project_dir=$cur_dir/$project_name
        project_src=$project_dir/src # 原始碼所在根目錄
        project_lib=$project_dir/lib #依賴jar所在目錄
        project_class=$project_dir/target # 編譯後class檔案存放根目錄
        echo "begin compile"
        echo $project_dir
        echo $project_src
        echo $project_lib
        echo $project_class

        # src目錄下的所有java檔案的名稱存入到 專案根目錄/src/sources.list檔案中 先檢查是否存在,如存在先刪除 
        rm -rf $project_src/sources.list
        # $project_src -name  '*.java'表示在 $project_src目錄下以及子目錄下尋找以.java目錄結尾的 檔案 並存放到source.list臨時檔案
        find $project_src  -name '*.java' > $project_src/sources.list
        echo "java source file >>>"
        cat $project_src/sources.list

        # 構建存放編譯好的class檔案的基目錄,先刪除目錄

        rm -rf $project_class
        mkdir $project_class

        # 組裝cp引數
        # 將所有的jar檔案絕對路徑記錄下來到lib.list檔案中
        rm -rf $project_lib/lib.list
        find $project_lib  -name '*.jar' > $project_lib/lib.list
        # 將當前目錄.新增進去
        cpvar=.:
        # 一行一行讀取lib.list檔案並去每行檔案路徑最終的檔名 ${line##*/}
        while read line
        do
            echo $line
            cpvar=${cpvar}${project_lib}"/"${line##*/}":"
            echo $cpvar
        done < $project_lib/lib.list

        echo "print cpvar "
        echo $cpvar
        # 刪除這個中間檔案
        rm -rf $project_lib/lib.list
        # 擷取cpvar最後一個字元:
        # 獲取cpvar字串長度
        length=${#cpvar}-1
        # 取 0 - length 長度的字串
        cpvar=${cpvar:0:length}
        echo $cpvar
         # 批量編譯java檔案 
        # 編碼:-encoding utf-8
        # 依賴庫以冒號:隔開 
        # -sourcepath 引數指定原始碼目錄跟目錄, @$project_src/sources.list 指定原始碼檔名
        javac -d $project_class -encoding UTF-8 -cp $cpvar  -g -sourcepath $project_src @$project_src/sources.list

        # 刪除 sources.list零時檔案
        rm -rf $project_src/sources.list

        #刪除存在的jar 若編譯過的話
        # rm $qddemo/qddemo.jar   
        cd $project_class
        jar -cvfm $project_class/${project_name}.jar $project_dir/MANIFEST.MF *
        chmod a+x $project_class/${project_name}.jar

        echo "將依賴包從"${project_lib}"複製到"${project_class}/lib"目錄下. "
        # 將依賴jar包從$project_lib 目錄 複製到 $project_target/lib目錄下
        cp -r  $project_lib $project_class/lib
}
compile
exit 0

note:指令碼和專案在同一目錄下,也即專案資料夾和編譯指令碼在同級目錄下 如
- 專案資料夾
- 指令碼檔案

注意:執行編譯指令碼必須在指令碼所在目錄執行編譯指令碼,因為指令碼基於當前目錄查詢工程目錄,進行編譯。

MANIFEST.MF檔案,放置在 專案根目錄下

指定了依賴的jar包檔案尋找的路徑在編譯後生成的jar檔案所在目錄下lib目錄下。

Manifest-Version: 1.0
Main-Class: org.vincent.App
Class-Path: lib/commons-collections-3.2.2.jar lib/commons-lang-2.6.jar

進入target目錄下執行生成的jar檔案:

java -jar javacDemo.jar

輸出:

start begin
true
true
start stop
Myname