RPNXCortado
C++23 JVM class-file, bytecode, validation, and JAR toolkit
Loading...
Searching...
No Matches
generate_hello_world.cpp
1// AI Generated 2026 Ryan P. Nicholl <rnicholl@protonmail.com>
2// SPDX-License-Identifier: Apache-2.0
3
6
7#include <cstddef>
8#include <cstdint>
9#include <exception>
10#include <filesystem>
11#include <fstream>
12#include <iostream>
13#include <span>
14#include <stdexcept>
15#include <string>
16#include <utility>
17#include <vector>
18
19int main(int argument_count, char** argument_values)
20{
21 try
22 {
23 if (argument_count > 2)
24 {
25 std::cerr << "usage: rpnx_cortado_generate_hello_world [output-directory]\n";
26 return 2;
27 }
28
29 std::filesystem::path const output_directory = argument_count == 2 ? std::filesystem::path(argument_values[1]) : std::filesystem::current_path();
30 std::filesystem::create_directories(output_directory);
31
32 rpnx::cortado::class_file_builder builder("HelloWorld", "java/lang/Object", {0, 52});
34 main_code.getstatic("java/lang/System", "out", "Ljava/io/PrintStream;").ldc_string("hello world").invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V").append< rpnx::cortado::opcode::return_ >();
35 static_cast< void >(builder.add_method("main", "([Ljava/lang/String;)V", rpnx::cortado::method_access_flags::is_public | rpnx::cortado::method_access_flags::is_static, main_code));
36
38 rpnx::cortado::label const false_result = choose_code.new_label();
39 choose_code.iload({0}).branch< rpnx::cortado::opcode::ifeq >(false_result).append< rpnx::cortado::opcode::iconst_1 >().append< rpnx::cortado::opcode::ireturn >();
40 choose_code.bind(false_result).append< rpnx::cortado::opcode::iconst_0 >().append< rpnx::cortado::opcode::ireturn >();
41 static_cast< void >(builder.add_method("choose", "(Z)I", rpnx::cortado::method_access_flags::is_public | rpnx::cortado::method_access_flags::is_static, choose_code));
42 rpnx::cortado::class_file const hello_world_class = builder.build();
43
44 std::vector< std::byte > const class_bytes = rpnx::cortado::serialize_class_file(hello_world_class);
45 std::string const manifest_text = "Manifest-Version: 1.0\nMain-Class: HelloWorld\n\n";
46 std::vector< std::byte > manifest_bytes;
47 manifest_bytes.reserve(manifest_text.size());
48 for (char const character : manifest_text)
49 {
50 manifest_bytes.push_back(static_cast< std::byte >(static_cast< std::uint8_t >(character)));
51 }
52
53 rpnx::cortado::jar_file hello_world_jar;
54 hello_world_jar.entries.push_back(rpnx::cortado::jar_entry{.name = "META-INF/MANIFEST.MF", .data = std::move(manifest_bytes), .compression = rpnx::cortado::compression_method::stored, .flags = rpnx::cortado::jar_entry_flags::utf8_names, .modification_date = rpnx::cortado::zip_dos_date{0x0021}});
55 hello_world_jar.entries.push_back(rpnx::cortado::jar_entry{.name = "HelloWorld.class", .data = class_bytes, .compression = rpnx::cortado::compression_method::deflated, .flags = rpnx::cortado::jar_entry_flags::utf8_names, .modification_date = rpnx::cortado::zip_dos_date{0x0021}});
56 std::vector< std::byte > const jar_bytes = rpnx::cortado::serialize_jar(hello_world_jar);
57
58 auto write_binary_file = [](std::filesystem::path const& path, std::span< std::byte const > bytes)
59 {
60 std::ofstream output(path, std::ios::binary | std::ios::trunc);
61 if (!output)
62 {
63 throw std::runtime_error("could not open " + path.string());
64 }
65 for (std::byte const byte : bytes)
66 {
67 output.put(static_cast< char >(std::to_integer< std::uint8_t >(byte)));
68 }
69 if (!output)
70 {
71 throw std::runtime_error("could not write " + path.string());
72 }
73 };
74
75 std::filesystem::path const class_path = output_directory / "HelloWorld.class";
76 std::filesystem::path const jar_path = output_directory / "hello-world.jar";
77 write_binary_file(class_path, class_bytes);
78 write_binary_file(jar_path, jar_bytes);
79 std::cout << "wrote " << class_path << '\n';
80 std::cout << "wrote " << jar_path << '\n';
81 return 0;
82 }
83 catch (std::exception const& error)
84 {
85 std::cerr << "rpnx_cortado_generate_hello_world: " << error.what() << '\n';
86 return 1;
87 }
88}
Deterministic constant-pool and symbolic class-file builders.
An owning symbolic class-file builder with a shared constant-pool interner.
Definition builders.hpp:673
An owning symbolic JVM code builder.
Definition builders.hpp:356
auto iload(local_variable_index index) -> code_builder &
Loads an int from a local using the shortest valid encoding.
auto bind(label value) -> code_builder &
Binds a label at the current instruction position.
label new_label()
Creates a fresh label owned by this builder.
auto getstatic(std::string owner, std::string name, std::string descriptor) -> code_builder &
Emits a symbolic getstatic instruction.
JAR-compatible ZIP serialization and deserialization APIs.
std::vector< std::byte > serialize_jar(jar_file const &value)
Serializes an archive as a non-Zip64 JAR-compatible ZIP file.
std::vector< std::byte > serialize_class_file(class_file const &value, class_file_write_options const &options={})
Serializes a class file using the big-endian JVM class-file format.
An owning, typed representation of one JVM class file.
One owning JAR/ZIP entry, with its data stored uncompressed in memory.
Definition types.hpp:283
An owning JAR archive representation.
Definition types.hpp:299
std::vector< jar_entry > entries
Entries in central-directory order; duplicate names remain distinct.
Definition types.hpp:300
A symbolic bytecode position owned by one code_builder.
Definition builders.hpp:34
A packed MS-DOS date value from a ZIP entry header.
Definition types.hpp:262