Skip to content

How to Compile a Java Project from a Batch Script (javac)

Learn how to automate Java compilation using Batch Scripts with javac, manage classpaths, create JAR files, and handle multi-file projects with package structures.

Automating Java compilation through Batch Script is essential for build workflows that need to run outside of heavyweight build tools like Maven or Gradle. Whether you are building a simple single-file utility, a multi-file project with package structure, or generating JAR archives, the javac compiler and jar tool can be orchestrated directly from a Batch Script for fast, lightweight, and transparent builds.

In this guide, we will explore how to compile Java projects from a Batch Script using javac, manage classpaths, create JAR files, and handle common build scenarios.

Prerequisites

Ensure the Java Development Kit (JDK) is installed and javac is on the system PATH:

@echo off
javac -version 2>nul
if %errorlevel% neq 0 (
    echo [ERROR] JDK not found. Install JDK and add to PATH.
    echo Download from: https://jdk.java.net/
    pause
    exit /b 1
)

Method 1: Compiling a Single Java File

@echo off
setlocal

set "source=src\HelloWorld.java"
set "output=bin"

if not exist "%source%" (
    echo [ERROR] Source file not found: %source%
    pause
    exit /b 1
)

echo Compiling %source%...

if not exist "%output%" mkdir "%output%"

javac -d "%output%" "%source%"

if %errorlevel%==0 (
    echo [SUCCESS] Compiled.
    echo Running...
    java -cp "%output%" HelloWorld
) else (
    echo [ERROR] Compilation failed.
    exit /b 1
)

pause

Key javac Options

Option Description
-d dir Output directory for compiled .class files
-cp path Classpath for dependencies
-source ver Source compatibility version (e.g., -source 11)
-target ver Target bytecode version
-Xlint Enable all recommended warnings
-encoding UTF-8 Source file encoding

Method 2: Compiling a Multi-File Project

For projects with multiple source files and package structure:

@echo off
setlocal enabledelayedexpansion

set "src_dir=src"
set "out_dir=bin"
set "lib_dir=lib"
set "sources_file=%temp%\java_sources_%random%.txt"

echo =============================================
echo   JAVA BUILD
echo =============================================
echo.

:: Verify source directory exists
if not exist "%src_dir%\" (
    echo [ERROR] Source directory not found: %src_dir%
    pause
    exit /b 1
)

:: Clean output directory
if exist "%out_dir%" rmdir /s /q "%out_dir%"
mkdir "%out_dir%"

:: Collect all .java files
echo [1/2] Finding source files...
dir /s /b "%src_dir%\*.java" > "%sources_file%" 2>nul

set "file_count=0"
for /f %%C in ('type "%sources_file%" ^| find /c /v ""') do set "file_count=%%C"

if %file_count%==0 (
    echo   [ERROR] No .java files found in %src_dir%.
    del "%sources_file%" 2>nul
    exit /b 1
)

echo   Found %file_count% source files.

:: Build classpath from lib directory
set "classpath="
if exist "%lib_dir%\" (
    for %%J in ("%lib_dir%\*.jar") do (
        if defined classpath (
            set "classpath=!classpath!;%%J"
        ) else (
            set "classpath=%%J"
        )
    )
)

:: Compile
echo [2/2] Compiling...
if defined classpath (
    javac -d "%out_dir%" -cp "!classpath!" -encoding UTF-8 -Xlint @"%sources_file%"
) else (
    javac -d "%out_dir%" -encoding UTF-8 -Xlint @"%sources_file%"
)
set "compile_result=!errorlevel!"

del "%sources_file%" 2>nul

if !compile_result!==0 (
    echo.
    echo [SUCCESS] Compiled %file_count% files to %out_dir%
) else (
    echo.
    echo [ERROR] Compilation failed.
    exit /b 1
)

pause

Method 3: Build and Create JAR

Compile the project and package it into an executable JAR:

@echo off
setlocal enabledelayedexpansion

set "app_name=MyApp"
set "main_class=com.example.Main"
set "src_dir=src"
set "out_dir=bin"
set "lib_dir=lib"
set "dist_dir=dist"
set "jar_file=%dist_dir%\%app_name%.jar"
set "sources_file=%temp%\java_sources_%random%.txt"

echo =============================================
echo   BUILD AND PACKAGE
echo =============================================
echo.

:: Clean
if exist "%out_dir%" rmdir /s /q "%out_dir%"
if exist "%dist_dir%" rmdir /s /q "%dist_dir%"
mkdir "%out_dir%"
mkdir "%dist_dir%"

:: Collect sources
dir /s /b "%src_dir%\*.java" > "%sources_file%" 2>nul

set "file_count=0"
for /f %%C in ('type "%sources_file%" ^| find /c /v ""') do set "file_count=%%C"

if %file_count%==0 (
    echo [ERROR] No .java files found in %src_dir%.
    del "%sources_file%" 2>nul
    exit /b 1
)

:: Build classpath
set "classpath="
if exist "%lib_dir%\" (
    for %%J in ("%lib_dir%\*.jar") do (
        if defined classpath (set "classpath=!classpath!;%%J") else (set "classpath=%%J")
    )
)

:: Compile
echo [1/3] Compiling %file_count% files...
if defined classpath (
    javac -d "%out_dir%" -cp "!classpath!" @"%sources_file%"
) else (
    javac -d "%out_dir%" @"%sources_file%"
)

del "%sources_file%" 2>nul

if !errorlevel! neq 0 (
    echo [FAIL] Compilation failed.
    exit /b 1
)
echo       Compiled.

:: Create manifest
echo [2/3] Creating manifest...
for /f "tokens=2 delims==" %%T in ('wmic os get LocalDateTime /value') do set "dt=%%T"
set "build_date=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%"

(
echo Manifest-Version: 1.0
echo Main-Class: %main_class%
echo Built-By: %USERNAME%
echo Build-Date: %build_date%
) > "%out_dir%\MANIFEST.MF"
:: Manifest files require a trailing newline
echo.>> "%out_dir%\MANIFEST.MF"

:: Create JAR
echo [3/3] Packaging JAR...
jar cfm "%jar_file%" "%out_dir%\MANIFEST.MF" -C "%out_dir%" .

if !errorlevel!==0 (
    for %%F in ("%jar_file%") do set "size=%%~zF"
    echo.
    echo [SUCCESS] JAR created: %jar_file% (!size! bytes^)
    echo Run with: java -jar %jar_file%
) else (
    echo [FAIL] JAR creation failed.
    exit /b 1
)

pause

Method 4: Full Build Pipeline with Tests

@echo off
setlocal enabledelayedexpansion

set "src_dir=src\main\java"
set "test_dir=src\test\java"
set "out_dir=build\classes"
set "test_out=build\test-classes"
set "lib_dir=lib"

echo =============================================
echo   JAVA BUILD PIPELINE
echo =============================================
echo.

:: Clean
echo [1/4] Cleaning...
if exist "build" rmdir /s /q "build"
mkdir "%out_dir%"
mkdir "%test_out%"
echo       Done.

:: Build classpath from lib/*.jar
set "classpath="
if exist "%lib_dir%\" (
    for %%J in ("%lib_dir%\*.jar") do (
        if defined classpath (set "classpath=!classpath!;%%J") else (set "classpath=%%J")
    )
)

:: Compile main sources
echo [2/4] Compiling sources...

if not exist "%src_dir%\" (
    echo [FAIL] Source directory not found: %src_dir%
    exit /b 1
)

set "main_sources=%temp%\main_sources_%random%.txt"
dir /s /b "%src_dir%\*.java" > "!main_sources!" 2>nul

set "src_count=0"
for /f %%C in ('type "!main_sources!" ^| find /c /v ""') do set "src_count=%%C"

if !src_count!==0 (
    echo [FAIL] No .java files found in %src_dir%.
    del "!main_sources!" 2>nul
    exit /b 1
)

if defined classpath (
    javac -d "%out_dir%" -cp "!classpath!" -encoding UTF-8 @"!main_sources!" 2> build\compile_errors.txt
) else (
    javac -d "%out_dir%" -encoding UTF-8 @"!main_sources!" 2> build\compile_errors.txt
)

if !errorlevel! neq 0 (
    echo [FAIL] Compilation failed:
    type build\compile_errors.txt
    del "!main_sources!" 2>nul
    exit /b 1
)
del "!main_sources!" 2>nul
echo       Compiled !src_count! source files.

:: Compile tests
echo [3/4] Compiling tests...
if not exist "%test_dir%\" (
    echo       No test directory. Skipping.
    goto run_tests
)

set "test_sources=%temp%\test_sources_%random%.txt"
dir /s /b "%test_dir%\*.java" > "!test_sources!" 2>nul

set "test_count=0"
for /f %%C in ('type "!test_sources!" ^| find /c /v ""') do set "test_count=%%C"

if !test_count!==0 (
    echo       No test files found. Skipping.
    del "!test_sources!" 2>nul
    goto run_tests
)

javac -d "%test_out%" -cp "%out_dir%;!classpath!" -encoding UTF-8 @"!test_sources!"
if !errorlevel! neq 0 (
    echo       [WARNING] Test compilation failed.
    del "!test_sources!" 2>nul
    goto run_tests
)
del "!test_sources!" 2>nul
echo       Compiled !test_count! test files.

:: Run tests
:run_tests
echo [4/4] Running tests...
if not exist "%test_out%\" (
    echo       No compiled tests to run.
) else (
    java -cp "%test_out%;%out_dir%;!classpath!" org.junit.runner.JUnitCore com.example.AllTests 2>nul
    if !errorlevel!==0 (
        echo       Tests passed.
    ) else (
        echo       [WARNING] Tests failed or JUnit not available.
    )
)

echo.
echo [BUILD COMPLETE]
pause

Method 5: Setting JAVA_HOME and Managing JDK Versions

@echo off
setlocal

:: Explicitly set JDK path
set "JAVA_HOME=C:\Program Files\Java\jdk-17"

if not exist "%JAVA_HOME%\bin\javac.exe" (
    echo [ERROR] JDK not found at: %JAVA_HOME%
    pause
    exit /b 1
)

set "PATH=%JAVA_HOME%\bin;%PATH%"

echo Using JDK: %JAVA_HOME%
javac -version
echo.

:: Build
javac -d bin src\*.java

pause

For projects requiring a specific JDK version:

@echo off
setlocal

set "required_major=17"

:: Check current version
set "current="
for /f "tokens=2" %%V in ('javac -version 2^>^&1') do set "current=%%V"

if not defined current (
    echo [ERROR] javac not found.
    pause
    exit /b 1
)

echo Current javac: %current%

:: Extract the major version number
for /f "tokens=1 delims=." %%M in ("%current%") do set "major=%%M"

if not "%major%"=="%required_major%" (
    echo [ERROR] JDK %required_major% required. Found major version: %major%
    pause
    exit /b 1
)

echo [OK] JDK version matches (major: %major%^).

Common Mistakes

The Wrong Way: Not Setting the Output Directory

:: WRONG - Class files are created next to source files
javac src\com\example\Main.java
:: Creates Main.class in src\com\example\, mixing source and output

Output Concern: Without -d, compiled .class files are placed alongside the .java source files, making the project messy and hard to package. Always use -d bin (or similar) to separate compiled output from source code.

The Wrong Way: Missing Classpath for Dependencies

:: WRONG - Fails if the project uses external JARs
javac -d bin src\com\example\Main.java
:: error: package org.apache.commons does not exist

If the project uses external libraries, you must include them in the classpath with -cp lib\*.jar or by building the classpath string explicitly.

Best Practices

  1. Separate source and output: Always use -d to send class files to a dedicated output directory.
  2. Use @file for source lists: Avoids command-line length limits with many source files.
  3. Build classpath dynamically: Loop over the lib directory to include all JARs.
  4. Set -encoding UTF-8: Prevents encoding-related compilation errors across different systems.
  5. Enable warnings with -Xlint: Catches common issues at compile time.

Conclusion

Compiling Java projects from a Batch Script using javac provides a lightweight, transparent build process without the overhead of Maven or Gradle. By collecting source files with dir /s /b, building classpaths from a library directory, and packaging output into JAR files with jar, Batch scripts can handle everything from simple single-file programs to multi-package projects. For larger projects with complex dependency management, consider using Maven or Gradle, but for straightforward builds and educational purposes, javac orchestrated by a Batch script is fast and effective.

Navigation