Skip to content

Commit 779cb40

Browse files
committed
Refactor build system: add file generation from templates, update Makefile, and enhance README. No more hardcoded ../../.. that needs manual adjusting, better portability.
1 parent 398bf13 commit 779cb40

File tree

11 files changed

+126
-95
lines changed

11 files changed

+126
-95
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
**/*.txt
1414

1515
# Crash logs generated by the JVM
16-
**/*.log
16+
**/*.log
17+
18+
# Generated by GenerateFiles.py
19+
jvm-unknown-unknown.json
20+
config.toml

GenerateFiles.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import os
2+
import platform
3+
4+
# get the absolute path of the current working directory
5+
current_directory = os.path.dirname(os.path.abspath(__file__))
6+
7+
# find .template files in this current directory
8+
template_files = []
9+
for root, dirs, files in os.walk(current_directory):
10+
for file in files:
11+
if file.endswith(".template"):
12+
template_files.append(os.path.join(root, file))
13+
14+
# copy them, removing the .template extension
15+
# replace all instances of "../../.." with the absolute path of the current working directory
16+
# Determine the appropriate dynamic library extension for the host platform
17+
if platform.system() == "Windows":
18+
lib_extension = ".dll"
19+
elif platform.system() == "Darwin": # macOS
20+
lib_extension = ".dylib"
21+
else: # Assume Linux or other Unix-like systems
22+
lib_extension = ".so"
23+
24+
for template_file in template_files:
25+
with open(template_file, 'r') as f:
26+
content = f.read()
27+
content = content.replace("../../..", current_directory)
28+
content = content.replace(".dylib", lib_extension)
29+
new_file_path = os.path.splitext(template_file)[0]
30+
with open(new_file_path, 'w') as f:
31+
f.write(content)

Makefile

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
# === Phony Targets ===
2-
.PHONY: all clean help rust clean-rust java-linker clean-java-linker \
3-
shim-metadata-gen clean-shim-metadata-gen \
4-
asm-processor clean-asm-processor \
5-
library clean-library
2+
.PHONY: all help clean rust-components rust clean-rust java-linker clean-java-linker \
3+
shim-metadata-gen clean-shim-metadata-gen asm-processor clean-asm-processor \
4+
library clean-library gen-files clean-gen-files
65

76
# === Terminal Colors ===
87
GREEN := \033[1;32m
98
CYAN := \033[1;36m
109
RESET := \033[0m
1110

11+
# === Directory Variables ===
12+
JAVA_LINKER_DIR := java-linker
13+
SHIM_METADATA_GEN_DIR := shim-metadata-gen
14+
ASM_PROCESSOR_DIR := asm-processor
15+
LIBRARY_DIR := library
16+
LIBRARY_JAR := $(LIBRARY_DIR)/build/libs/library-0.1.0.jar
17+
1218
# === Default Target ===
13-
all: rust java-linker asm-processor
19+
all: rust gen-files java-linker asm-processor
1420
@echo "$(GREEN)✨ Build complete! ✨$(RESET)"
1521

1622
# === Help ===
@@ -20,15 +26,22 @@ help:
2026
@echo "Available targets:"
2127
@echo " make all - Build all components"
2228
@echo " make clean - Clean all components"
29+
@echo " make rust-components - Install needed Rust components"
2330
@echo " make rust - Build the Rust root project"
2431
@echo " make java-linker - Build the Java Linker subproject"
2532
@echo " make shim-metadata-gen - Generate library shim metadata"
2633
@echo " make asm-processor - Build the ASM processor"
2734
@echo " make library - Build the standard library shim"
35+
@echo " make gen-files - Generate necessary files from templates"
2836
@echo " make clean-* - Clean individual components"
2937

38+
# === Needed rust components ===
39+
rust-components:
40+
@echo "$(CYAN)🔧 Installing Rust components...$(RESET)"
41+
rustup component add rust-src rustc-dev llvm-tools-preview
42+
3043
# === Rust root project (Cargo) ===
31-
rust: shim-metadata-gen
44+
rust: $(SHIM_METADATA_GEN_DIR)/core.json rust-components
3245
@echo "$(CYAN)📦 Building Rust root project...$(RESET)"
3346
cargo build
3447

@@ -39,40 +52,52 @@ clean-rust:
3952
# === Java Linker Subproject ===
4053
java-linker:
4154
@echo "$(CYAN)📦 Building Java Linker...$(RESET)"
42-
cd java-linker && cargo build
55+
cd $(JAVA_LINKER_DIR) && cargo build
4356

4457
clean-java-linker:
4558
@echo "$(CYAN)🧹 Cleaning Java Linker...$(RESET)"
46-
cd java-linker && cargo clean
59+
cd $(JAVA_LINKER_DIR) && cargo clean
4760

48-
# === Library shim metadata generator ===
49-
# needs to clean first so unzip doesn't prompt for overwrite
50-
shim-metadata-gen: clean-library library
51-
@echo "$(CYAN)🔧 Generating shim metadata...$(RESET)"
52-
cd shim-metadata-gen && rm -f core.json && cargo run -- ../library/build/libs/library-0.1.0.jar ./core.json
61+
# === Library Shim Metadata Generator ===
62+
$(SHIM_METADATA_GEN_DIR)/core.json: library
63+
@echo "$(CYAN)🛠️ Generating library shim metadata...$(RESET)"
64+
cd $(SHIM_METADATA_GEN_DIR) && cargo run -- ../$(LIBRARY_JAR) ./core.json
5365

5466
clean-shim-metadata-gen:
5567
@echo "$(CYAN)🧹 Cleaning shim-metadata-gen...$(RESET)"
56-
cd shim-metadata-gen && cargo clean
68+
cd $(SHIM_METADATA_GEN_DIR) && cargo clean
69+
rm -f $(SHIM_METADATA_GEN_DIR)/core.json
5770

5871
# === ASM Processor (Gradle) ===
5972
asm-processor:
6073
@echo "$(CYAN)⚙️ Building ASM processor...$(RESET)"
61-
cd asm-processor && gradle shadowJar
74+
cd $(ASM_PROCESSOR_DIR) && gradle shadowJar
6275

6376
clean-asm-processor:
6477
@echo "$(CYAN)🧹 Cleaning ASM processor...$(RESET)"
65-
cd asm-processor && gradle clean
78+
cd $(ASM_PROCESSOR_DIR) && gradle clean
6679

6780
# === Standard Library Shim (Gradle) ===
68-
library:
81+
library: $(LIBRARY_JAR)
82+
83+
$(LIBRARY_JAR):
6984
@echo "$(CYAN)📚 Building standard library shim...$(RESET)"
70-
cd library && gradle build && cd build/distributions && unzip library-0.1.0.zip
85+
cd $(LIBRARY_DIR) && gradle build && cd build/distributions && unzip -o library-0.1.0.zip
7186

7287
clean-library:
7388
@echo "$(CYAN)🧹 Cleaning library shim...$(RESET)"
74-
cd library && gradle clean
89+
cd $(LIBRARY_DIR) && gradle clean
90+
91+
# === Generate files from templates ==
92+
gen-files: clean-gen-files
93+
@echo "$(CYAN)🛠️ Generating files from templates...$(RESET)"
94+
python3 GenerateFiles.py
95+
@echo "$(CYAN)🛠️ Files generated!$(RESET)"
96+
97+
clean-gen-files:
98+
@echo "$(CYAN)🧹 Cleaning template generated files...$(RESET)"
99+
rm -f jvm-unknown-unknown.json config.toml
75100

76101
# === Clean All ===
77-
clean: clean-rust clean-java-linker clean-asm-processor clean-library clean-shim-metadata-gen
78-
@echo "$(GREEN)🧼 All clean!$(RESET)"
102+
clean: clean-rust clean-java-linker clean-asm-processor clean-library clean-shim-metadata-gen clean-gen-files
103+
@echo "$(GREEN)🧼 All clean!$(RESET)"

Readme.md

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](https://opensource.org/licenses/MIT)
44

5-
Welcome! This project provides a custom Rust compiler backend (`rustc_codegen_jvm`) that compiles Rust code into Java Virtual Machine (JVM) bytecode. This allows Rust programs to run on the JVM. Currently, the generated bytecode supports JRE 8 and later versions.
5+
Welcome! This project provides a custom Rust compiler backend (`rustc_codegen_jvm`) that compiles Rust code into Java Virtual Machine (JVM) bytecode. This allows Rust programs to run on the JVM. Currently, the generated bytecode supports JVM 8 and later versions.
66

77
## How It Works
88

@@ -34,67 +34,49 @@ This backend currently supports a subset of Rust features:
3434
* Checked addition and subtraction (`checked_add`, `checked_sub`) returning `(result, overflowed_bool)` tuples.
3535
* ✅ Comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`).
3636
* ✅ Bitwise operations (`&`, `|`, `^`, `<<`, `>>`).
37-
* ✅ Basic control flow: `if`/`else` statements, `panic!` / `assert!` (with simple string messages).
37+
* ✅ Basic control flow: `if`/`else` statements, `panic!` / `assert!` (including multiple arguments and formatting (`{}`) of most rust primitives)
3838
* ✅ Calling other `static` functions within the same crate (including recursion).
3939
* ✅ Basic variable assignment (`let x = y;`).
4040
* ✅ Arrays and slices.
41+
* ✅ Floats (`f32`, `f64`).
4142
* ✅ Generating executable `.jar` files for binary crates.
4243

4344
### Next Milestone:
4445
🚧 **Full support for the `core` crate** is the next major goal.
4546

4647
## Prerequisites
4748

48-
* **Rust Nightly:** Ensure you are using the latest **nightly** Rust toolchain. You can set this up with `rustup default nightly`.
49-
* **Rust Components:** Install necessary components:
50-
```bash
51-
rustup component add rust-src rustc-dev llvm-tools-preview
52-
```
53-
*(Note: The `rust-toolchain.toml` file in the repository should handle this automatically if you use `cargo` within the project.)*
49+
* **Rust Nightly:** Ensure you are using the latest **nightly** Rust toolchain. You can set this up with `rustup default nightly`. Some rust components are needed but will be automatically installed by the Makefile.
5450
* **Java Development Kit (JDK):** A working JDK (version 8 or later recommended) is required to run the generated `.jar` files and the `asm-processor`. Make sure `java` is in your PATH.
5551
* **Gradle:** Required to build the `asm-processor` Kotlin project. Make sure `gradle` is in your PATH.
52+
* **Python 3:** Required to run the integration tests and generate files from templates. Make sure `python3` is in your PATH.
5653

5754
## Building the Toolchain
5855

59-
1. **Run Setup Script (if needed):**
60-
* The `setup.sh` script mainly adds rustup components, which `rust-toolchain.toml` might already handle. Ensure the components listed in Prerequisites are installed.
61-
2. **Build All Components:**
56+
1. **Build All Components:**
6257
* You can use the provided Makefile or build script:
6358
```bash
6459
# Using Make
6560
make all
6661
```
6762
* This will:
68-
* Build the main `rustc_codegen_jvm` library (`target/debug/librustc_codegen_jvm.dylib`).
63+
* Build the main `rustc_codegen_jvm` library (`target/debug/librustc_codegen_jvm.[dll/dylib/so]`).
6964
* Build the `java-linker` (`java-linker/target/debug/java-linker`).
7065
* Build the `asm-processor` (`asm-processor/build/libs/asm-processor-*.jar`).
66+
* Build the Kotlin shim of the Rust core library (`library`).
67+
* Generate the `config.toml` and `jvm-unknown-unknown.json` files from their templates.
68+
7169

7270
## Using the Toolchain (Compiling Another Rust Project)
7371

7472
To compile *your own* Rust project using this backend:
7573

76-
1. **Get the Toolchain:** Clone this repository and build it as described above. Let's assume you cloned it to `/path/to/rustc_codegen_jvm`. Ensure you build the toolchain first, as described in the previous section.
74+
1. **Get the Toolchain:** Clone this repository and build it as described above. Ensure you build the toolchain first, as described in the previous section, by running `make all`. You will need to re-run `make gen-files` if you change the absolute path of where this repository is stored since building.
7775

7876

7977
2. **Configure Your Rust Project:**
8078
* In your *own* Rust project's directory, create a `.cargo/config.toml` file (if it doesn't exist).
81-
* Add the following content to the file:
82-
```toml
83-
[build]
84-
rustflags = [
85-
"-Z", "codegen-backend=/path/to/rustc_codegen_jvm/target/debug/librustc_codegen_jvm.dylib",
86-
"-C", "linker=/path/to/rustc_codegen_jvm/java-linker/target/debug/java-linker",
87-
"-C", "link-args=/path/to/rustc_codegen_jvm/library/build/distributions/library-0.1.0/lib/library-0.1.0.jar /path/to/rustc_codegen_jvm/library/build/distributions/library-0.1.0/lib/kotlin-stdlib-2.1.20.jar --asm-processor /path/to/rustc_codegen_jvm/asm-processor/build/libs/asm-processor-1.0-SNAPSHOT-all.jar --known-good kotlin-stdlib"
88-
]
89-
90-
# Throwing a JVM exception will unwind and give a stack trace, no need for rust to handle unwinding.
91-
[profile.debug]
92-
panic = "abort"
93-
94-
[profile.release]
95-
panic = "abort"
96-
```
97-
* **Important:** Replace `/path/to/rustc_codegen_jvm/...` with the path to where you cloned the repository. If you're not on macOS, changed `.dylib` to `.so` for Linux or `.dll` for Windows.
79+
* Copy the contents from the `config.toml` file generated specifically for your system, that can be found in the root of this project after running `make all`. If since running make, you've moved this repo to a different directory, you'll need to run at least `make gen-files`.
9880

9981
3. **Build Your Project:**
10082
* Run the standard Cargo build command, targeting the host target (using the `jvm-unknown-unknown` target is an emerging feature and means you can't even use `core`, for now, so not recommended). Cargo will read the `.cargo/config.toml` and use the specified target and flags automatically.
@@ -117,15 +99,14 @@ To compile *your own* Rust project using this backend:
11799

118100
This project includes integration tests managed by a Python script.
119101

120-
1. **Ensure Toolchain is Built:** Build the project using `make all`.
121-
2. **Check Target JSON:** Make sure the `jvm-unknown-unknown.json` file in the *root* of this repository has the **relative paths** starting with `/path/to/rustc_codegen_jvm/` for the linker and backend, as the tester expects this structure when running tests from subdirectories. If you changed them to absolute paths for external use, change them back temporarily.
122-
3. **Run the Tester:**
102+
1. **Ensure Toolchain is Built:** Build the project using `make all`. If you've changed the path of the repository, run `make gen-files` to regenerate the configuration files.
103+
2. **Run the Tester:**
123104
```bash
124105
python3 Tester.py
125106
# For release mode tests:
126107
# python3 Tester.py --release
127108
```
128-
4. **Check Output:** Look for the final "✅ All tests passed!" message. If tests fail, the script will generate `.generated` files in the respective test directories (`tests/binary/*`) containing error details or output diffs.
109+
3. **Check Output:** Look for the final "✅ All tests passed!" message. If tests fail, the script will generate `.generated` files in the respective test directories (`tests/binary/*`) containing error details or output diffs.
129110
130111
## Project Structure
131112
@@ -141,8 +122,10 @@ This project includes integration tests managed by a Python script.
141122
* `library/`: Source code for a minimal Kotlin-based implementation of the Rust core library. This serves as a temporary substitute to bootstrap the project until the backend can fully compile the Rust core library itself.
142123
* `shim-metadata-gen`: A tool for generating metadata for the Kotlin core library, called at compiletime to provide nessecary info (descriptors) to the codegen backend. It's generated metadata is embedded in the generated library, so not needed at runtime.
143124
* `core.json`: Metadata for the core library, generated by this tool.
144-
* `jvm-unknown-unknown.json`: The Rust target specification file.
125+
* `jvm-unknown-unknown.json.template`: The template for Rust target specification file (currently experimental & not recommended, use `config.toml` in your project instead).
126+
* `config.toml.template`: The template for the Cargo configuration file for the toolchain.
145127
* `Tester.py`: Python script for running integration tests.
128+
* `GenerateFiles.py` : Python script for generating the `config.toml` file and the `jvm-unknown-unknown.json` file from their templates, making them suited to your system.
146129
* `Makefile` Scripts for building the entire toolchain.
147130
* `setup.sh`: Script to install Rust components.
148131
* `Cargo.toml`, `Cargo.lock`: Rust package definition and dependencies for the backend.

config.toml.template

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[build]
2+
rustflags = [
3+
"-Z", "codegen-backend=../../../target/debug/librustc_codegen_jvm.dylib",
4+
"-C", "linker=../../../java-linker/target/debug/java-linker",
5+
"-C", "link-args=../../../library/build/distributions/library-0.1.0/lib/library-0.1.0.jar ../../../library/build/distributions/library-0.1.0/lib/kotlin-stdlib-2.1.20.jar --asm-processor ../../../asm-processor/build/libs/asm-processor-1.0-SNAPSHOT-all.jar --known-good kotlin-stdlib"
6+
]
7+
8+
# Throwing a JVM exception will unwind and give a stack trace, no need for rust to handle unwinding.
9+
[profile.debug]
10+
panic = "abort"
11+
12+
[profile.release]
13+
panic = "abort"
File renamed without changes.

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
22
channel = "nightly"
3-
components = ["rustc-dev", "llvm-tools-preview"]
3+
components = ["rustc-dev", "rust-src", "llvm-tools-preview"]

setup.sh

Lines changed: 0 additions & 1 deletion
This file was deleted.

shim-metadata-gen/core.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
{
2-
"arguments_new_const": {
3-
"descriptor": "([Ljava/lang/String;)Ljava/lang/String;",
2+
"panic_fmt": {
3+
"descriptor": "(Ljava/lang/String;)V",
44
"is_static": true
55
},
6-
"core_fmt_rt_argument_new_display_i32": {
7-
"descriptor": "(I)Ljava/lang/String;",
6+
"arguments_new_const": {
7+
"descriptor": "([Ljava/lang/String;)Ljava/lang/String;",
88
"is_static": true
99
},
1010
"core_fmt_rt_argument_new_display": {
1111
"descriptor": "(Ljava/lang/Object;)Ljava/lang/String;",
1212
"is_static": true
1313
},
14-
"core_fmt_rt_argument_new_display_f64": {
15-
"descriptor": "(D)Ljava/lang/String;",
14+
"core_fmt_rt_argument_new_display_i32": {
15+
"descriptor": "(I)Ljava/lang/String;",
1616
"is_static": true
1717
},
18-
"core_fmt_rt_argument_new_display_bool": {
19-
"descriptor": "(Z)Ljava/lang/String;",
18+
"core_fmt_rt_argument_new_display_f64": {
19+
"descriptor": "(D)Ljava/lang/String;",
2020
"is_static": true
2121
},
2222
"arguments_new_v1": {
2323
"descriptor": "([Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;",
2424
"is_static": true
2525
},
26-
"panic_fmt": {
27-
"descriptor": "(Ljava/lang/String;)V",
26+
"core_fmt_rt_argument_new_display_bool": {
27+
"descriptor": "(Z)Ljava/lang/String;",
2828
"is_static": true
2929
}
3030
}

tests/binary/is_even_plus_one/.cargo/config.toml

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)