19int main(
int argument_count,
char** argument_values)
23 if (argument_count > 2)
25 std::cerr <<
"usage: rpnx_cortado_generate_hello_world [output-directory]\n";
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);
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));
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));
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)
50 manifest_bytes.push_back(
static_cast< std::byte
>(
static_cast< std::uint8_t
>(character)));
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}});
58 auto write_binary_file = [](std::filesystem::path
const& path, std::span< std::byte const > bytes)
60 std::ofstream output(path, std::ios::binary | std::ios::trunc);
63 throw std::runtime_error(
"could not open " + path.string());
65 for (std::byte
const byte : bytes)
67 output.put(
static_cast< char >(std::to_integer< std::uint8_t >(
byte)));
71 throw std::runtime_error(
"could not write " + path.string());
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';
83 catch (std::exception
const& error)
85 std::cerr <<
"rpnx_cortado_generate_hello_world: " << error.what() <<
'\n';
Deterministic constant-pool and symbolic class-file builders.
An owning symbolic class-file builder with a shared constant-pool interner.
An owning symbolic JVM code builder.
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.
An owning JAR archive representation.
std::vector< jar_entry > entries
Entries in central-directory order; duplicate names remain distinct.
A symbolic bytecode position owned by one code_builder.
A packed MS-DOS date value from a ZIP entry header.