WSL Build Guide for nativify
This guide provides step-by-step instructions for building and testing nativify in WSL 2 Ubuntu, bypassing Windows LLVM issues.
System Configuration:
- WSL Version: WSL 2
- Distribution: Ubuntu 20.04 or later
- Project Location: /mnt/d/projects/masxinling-plus (Windows D:\ drive)
- Target Platform: linux-x86_64
Estimated Time: 15-30 minutes (depending on download speeds)
Table of Contents
- Prerequisites Check
- Phase 1: WSL Environment Setup
- Phase 2: Install Java 21
- Phase 3: Install Maven
- Phase 4: Install LLVM 20 and Clang
- Phase 5: Configure Environment Variables
- Phase 6: Build the Project
- Phase 7: Run Tests
- Phase 8: Verify Output
- Troubleshooting
- Performance Optimization (Optional)
Prerequisites Check
Before starting, ensure you have:
- Complete WSL 2 installed on Windows
- Complete Ubuntu distribution installed in WSL
- Complete Windows project files accessible at D:\projects\masxinling-plus
To verify WSL version:
Should show WSL version 2.
Phase 1: WSL Environment Setup
Step 1.1: Open WSL Terminal
Open Ubuntu terminal (you can use Windows Terminal or search for "Ubuntu" in Start menu).
Step 1.2: Navigate to Project Directory
Step 1.3: Verify Access to Project Files
Expected output: You should see files like pom.xml, README.md, CLAUDE.md, etc.
Phase 2: Install Java 21
Step 2.1: Update Package Lists
What this does: Updates the list of available packages and their versions.
Step 2.2: Install OpenJDK 21
What this does: Installs Java Development Kit 21, required for building the project.
Note: This may take 2-5 minutes depending on your connection.
Step 2.3: Verify Java Installation
Expected output:
Step 2.4: Verify Java Compiler
Expected output:
Step 2.5: Check JAVA_HOME (Optional but Recommended)
If empty, set it:
Expected output: /usr/lib/jvm/java-21-openjdk-amd64 (or similar)
Phase 3: Install Maven
Step 3.1: Install Maven
What this does: Installs Apache Maven build tool.
Note: This may take 1-3 minutes.
Step 3.2: Verify Maven Installation
Expected output:
Important: Verify that Maven is using Java 21 (shown in output).
Phase 4: Install LLVM 20 and Clang
Step 4.1: Install LLVM 20
What this does: Installs LLVM 20 compiler infrastructure.
Note: This may take 3-7 minutes depending on connection.
Step 4.2: Install Clang 20
What this does: Installs Clang C/C++ compiler (required for native code generation).
Step 4.3: Verify LLVM Installation
Expected output:
Step 4.4: Verify Clang Installation
Expected output:
Step 4.5: Verify Other LLVM Tools
Expected output: Should show LLVM version 20.x.x
Phase 5: Configure Environment Variables
Step 5.1: Add LLVM to PATH (Temporary)
What this does: Makes LLVM tools available without version suffix (e.g., llc instead of llc-20).
Step 5.2: Verify PATH Configuration
Expected output: /usr/lib/llvm-20/bin/llc
Test without version suffix:
Should show LLVM 20.x.x
Step 5.3: Make PATH Permanent
Add LLVM to your shell configuration:
What this does: Ensures LLVM is in PATH every time you open a new WSL terminal.
Step 5.4: Reload Shell Configuration (Optional)
Or simply close and reopen your WSL terminal.
Step 5.5: Set JAVA_HOME Permanently (If Not Already Set)
Adjust path if your Java installation is different (check with which java).
Phase 6: Build the Project
Step 6.1: Navigate to Project Directory
Step 6.2: Clean Any Previous Windows Builds
What this does: Removes any artifacts from previous Windows builds that might cause conflicts.
Step 6.3: Build with Linux Platform Flag
What this does:
- clean: Removes previous build artifacts
- install: Builds all modules and installs to local Maven repository
- -Djavacpp.platform=linux-x86_64: Tells ByteDeco to use Linux native libraries
Expected Duration: 3-10 minutes on first build
Expected Output (at the end):
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: X min XX s
Step 6.4: Verify Build Artifacts
Expected output: Should show the CLI JAR file (approximately 50-100 MB).
Phase 7: Run Tests
Step 7.1: Verify Test JAR Exists
Expected output: obf-test.jar should exist in the project root.
Step 7.2: Run Obfuscation on Test JAR
mvn exec:java -pl nativify-cli \
-Dexec.mainClass="dev.haedus.nativify.CLIMain" \
-Dexec.args="-i obf-test.jar -o obfuscated.jar -compileFor linux"
What this does:
- Takes obf-test.jar as input
- Compiles marked methods to native Linux code
- Generates obfuscated.jar with native libraries embedded
Expected Duration: 1-5 minutes
Expected Output:
[INFO] Processing input JAR: obf-test.jar
[INFO] Compiling methods to LLVM IR...
[INFO] Running LLVM optimizations...
[INFO] Generating native library for linux...
[INFO] Writing output JAR: obfuscated.jar
[INFO] BUILD SUCCESS
Step 7.3: Verify Obfuscated JAR Created
Expected output: obfuscated.jar should exist and be similar size to obf-test.jar.
Step 7.4: Check Native Libraries in JAR
Expected output: Should show .so files (Linux shared libraries):
Phase 8: Verify Output
Step 8.1: Run Obfuscated JAR
Expected Output (SUCCESS):
If you see this message: Complete Build and obfuscation successful!
Step 8.2: Alternative - Run with Verbose Output
For debugging, you can run with Java logging:
This shows JNI calls and native library loading.
Troubleshooting
Issue 1: "LLVM not found" During Build
Symptom: Error about missing llc, opt, or clang
Solution:
# Check if LLVM is in PATH
which llc
# If not found, add to PATH
export PATH=/usr/lib/llvm-20/bin:$PATH
# Verify
llc --version
Alternative: Specify LLVM directory explicitly:
mvn exec:java -pl nativify-cli \
-Dexec.mainClass="dev.haedus.nativify.CLIMain" \
-Dexec.args="-i obf-test.jar -o obfuscated.jar -compileFor linux -llvmDir /usr/lib/llvm-20/bin"
Issue 2: "Permission Denied" Errors
Symptom: Cannot write to directories or execute commands
Solution:
# Make sure you're not trying to write to protected Windows directories
# Work within /mnt/d/projects/... (should have write access)
# If needed, check permissions
ls -la obf-test.jar
Issue 3: Maven Build Fails with "Cannot Find Symbol"
Symptom: Compilation errors about missing classes
Solution:
# Ensure you're using Java 21
java -version
# Clean and rebuild
mvn clean install -Djavacpp.platform=linux-x86_64
Issue 4: Tests Fail - "Successfully passed every test!" Not Shown
Symptom: Obfuscated JAR runs but shows errors or different output
Possible Causes: 1. Sign extension issues (should be fixed in latest code) 2. Missing native libraries 3. Platform mismatch
Debug Steps:
# Generate LLVM IR for inspection
mvn exec:java -pl nativify-cli \
-Dexec.mainClass="dev.haedus.nativify.CLIMain" \
-Dexec.args="-i obf-test.jar -o obfuscated.jar -ll output.ll"
# Check IR file
less output.ll
Issue 5: Slow Build Performance
Symptom: Build takes much longer than expected
Cause: Cross-filesystem access between Windows and WSL can be slow.
Solutions: 1. Temporary: Use WSL 2's improved I/O (should be fast enough) 2. Long-term: Copy project to WSL filesystem (see Performance Optimization below)
Issue 6: UnsatisfiedLinkError When Running JAR
Symptom:
Solution:
# Verify native libraries are in JAR
jar tf obfuscated.jar | grep ".so"
# If missing, rebuild with correct platform flag
mvn clean install -Djavacpp.platform=linux-x86_64
Performance Optimization (Optional)
If builds are too slow accessing files from /mnt/d/..., consider copying the project to WSL's native filesystem:
Option A: Copy to WSL Filesystem
# Create projects directory in WSL home
mkdir -p ~/projects
# Copy project (preserves permissions and attributes)
cp -r /mnt/d/projects/masxinling-plus ~/projects/
# Navigate to new location
cd ~/projects/masxinling-plus
# Build (will be faster)
mvn clean install -Djavacpp.platform=linux-x86_64
Pros: - Complete Much faster builds (native filesystem I/O) - Complete Better performance for Git operations - Complete No cross-filesystem overhead
Cons: - Incomplete Need to keep Windows and WSL copies in sync - Incomplete Uses WSL disk space (ext4 virtual disk)
Option B: Enable WSL 2 Advanced Settings
Create or edit C:\Users\<YourUsername>\.wslconfig on Windows:
Then restart WSL:
Reopen WSL terminal - performance should improve.
Quick Reference Commands
Full Build and Test Workflow
# 1. Navigate to project
cd /mnt/d/projects/masxinling-plus
# 2. Build
mvn clean install -Djavacpp.platform=linux-x86_64
# 3. Test
mvn exec:java -pl nativify-cli \
-Dexec.mainClass="dev.haedus.nativify.CLIMain" \
-Dexec.args="-i obf-test.jar -o obfuscated.jar -compileFor linux"
# 4. Verify
java -jar obfuscated.jar
# Expected: "Successfully passed every test!"
Environment Variables Checklist
# Check Java
echo $JAVA_HOME
java -version
# Check Maven
mvn -version
# Check LLVM
echo $PATH | grep llvm
llc --version
opt --version
clang --version
Clean Rebuild (When Things Go Wrong)
# Clean everything
mvn clean
# Clear Maven cache (if really stuck)
rm -rf ~/.m2/repository/dev/haedus/nativify
# Rebuild from scratch
mvn clean install -Djavacpp.platform=linux-x86_64
Multi-Platform Compilation
Once WSL setup is complete, you can compile for multiple platforms:
mvn exec:java -pl nativify-cli \
-Dexec.mainClass="dev.haedus.nativify.CLIMain" \
-Dexec.args="-i obf-test.jar -o obfuscated.jar -compileFor windows,linux"
This generates native libraries for both Windows and Linux in the same JAR.
Success Criteria
You've successfully completed the WSL setup if:
- Complete
mvn clean install -Djavacpp.platform=linux-x86_64completes without errors - Complete Obfuscation command generates
obfuscated.jarwith Linux.sofiles - Complete Running
java -jar obfuscated.jarshows: "Successfully passed every test!" - Complete Future builds can be done entirely in WSL, bypassing Windows LLVM issues
Additional Notes
Why WSL Over Windows for This Project?
- LLVM Integration: Linux LLVM tools are more stable and easier to configure
- Native Library Generation: Clang on Linux handles JNI better
- Build Performance: Native filesystem I/O is faster
- Debugging: Better tooling for inspecting LLVM IR and native libraries
Keeping Windows and WSL Builds Separate
- Windows builds: Use
windows-x86_64platform flag - WSL builds: Use
linux-x86_64platform flag - Always run
mvn cleanwhen switching between platforms
Next Steps After Setup
- Test with your own JAR files
- Experiment with optimization levels (
-O0,-O1,-O2,-O3) - Profile performance differences between bytecode and native code
- Explore LLVM IR output with
-ll output.llflag
Support and Resources
- Project Documentation: See the CLI Reference, Usage Guide, and Benchmarks
- LLVM Documentation: https://llvm.org/docs/
- WSL Documentation: https://learn.microsoft.com/en-us/windows/wsl/
Last Updated: 2025-11-22 Tested On: WSL 2 Ubuntu 22.04, Java 21, Maven 3.9.x, LLVM 20.1.7