|
| 1 | +use std::fs; |
| 2 | +use std::io::Write; |
| 3 | +use std::path::PathBuf; |
| 4 | +use std::process::Command; |
| 5 | + |
| 6 | +const C_GENERATOR: &str = r#" |
| 7 | +#include <stdio.h> |
| 8 | +#include <stdlib.h> |
| 9 | +#include <string.h> |
| 10 | +#include <errno.h> |
| 11 | +
|
| 12 | +/* Heresy C generator: |
| 13 | + - Writes alpha.c, beta.c, runner.c |
| 14 | + - Compiles them to alpha.o, beta.o, runner.o |
| 15 | + - Links into heresy_exe |
| 16 | + - Optionally tries to call cargo again (disabled by env HERESY_ONCE=1) |
| 17 | +*/ |
| 18 | +
|
| 19 | +static const char *ALPHA_SRC = |
| 20 | +"#include <stdio.h>\n" |
| 21 | +"void alpha(void){ puts(\"Alpha says hello from heresy.\"); }\n"; |
| 22 | + |
| 23 | +static const char *BETA_SRC = |
| 24 | +"#include <stdio.h>\n" |
| 25 | +"void beta(void){ puts(\"Beta whispers: cargo is a Makefile.\"); }\n"; |
| 26 | + |
| 27 | +static const char *RUNNER_SRC = |
| 28 | +"#include <stdio.h>\n" |
| 29 | +"void alpha(void); void beta(void);\n" |
| 30 | +"int main(void){ puts(\">>> runner.c starting\"); alpha(); beta(); puts(\">>> runner.c done\"); return 0; }\n"; |
| 31 | + |
| 32 | +static int write_file(const char* path, const char* contents) { |
| 33 | + FILE *f = fopen(path, "wb"); |
| 34 | + if(!f){ fprintf(stderr, \"write_file: fopen %s failed: %s\\n\", path, strerror(errno)); return -1; } |
| 35 | + size_t n = fwrite(contents, 1, strlen(contents), f); |
| 36 | + if(n != strlen(contents)){ fprintf(stderr, \"write_file: short write %s\\n\", path); fclose(f); return -1; } |
| 37 | + fclose(f); |
| 38 | + return 0; |
| 39 | +} |
| 40 | + |
| 41 | +static int run(const char *cmd) { |
| 42 | + int rc = system(cmd); |
| 43 | + if(rc != 0){ |
| 44 | + fprintf(stderr, \"cmd failed (%d): %s\\n\", rc, cmd); |
| 45 | + return -1; |
| 46 | + } |
| 47 | + return 0; |
| 48 | +} |
| 49 | + |
| 50 | +int main(void){ |
| 51 | + puts("🔧 C-generator: emitting tiny C project (alpha,beta,runner)..."); |
| 52 | + if(write_file("alpha.c", ALPHA_SRC) < 0) return 1; |
| 53 | + if(write_file("beta.c", BETA_SRC) < 0) return 1; |
| 54 | + if(write_file("runner.c",RUNNER_SRC)< 0) return 1; |
| 55 | + |
| 56 | + puts("🧱 compiling objects..."); |
| 57 | + if(run("gcc -Wall -g -O0 -c alpha.c -o alpha.o")) return 1; |
| 58 | + if(run("gcc -Wall -g -O0 -c beta.c -o beta.o" )) return 1; |
| 59 | + if(run("gcc -Wall -g -O0 -c runner.c -o runner.o")) return 1; |
| 60 | + |
| 61 | + puts("🔗 linking heresy_exe..."); |
| 62 | + if(run("gcc -g -o heresy_exe alpha.o beta.o runner.o")) return 1; |
| 63 | + puts("🎉 built ./heresy_exe"); |
| 64 | + |
| 65 | + /* Optional ouroboros poke (disabled by HERESY_ONCE=1) */ |
| 66 | + const char* once = getenv("HERESY_ONCE"); |
| 67 | + if(!once || strcmp(once, "1") != 0){ |
| 68 | + puts("♻️ (would re-invoke cargo here, but we're polite in CI)"); |
| 69 | + // run("cargo build --quiet"); // uncomment for maximum looping chaos (not recommended) |
| 70 | + } else { |
| 71 | + puts("🛑 recursion guard (HERESY_ONCE=1) active; skipping cargo re-entry."); |
| 72 | + } |
| 73 | + return 0; |
| 74 | +} |
| 75 | +"#; |
| 76 | +
|
| 77 | +fn sh(cmd: &mut Command) -> std::io::Result<()> { |
| 78 | + let status = cmd.status()?; |
| 79 | + if !status.success() { |
| 80 | + Err(std::io::Error::new( |
| 81 | + std::io::ErrorKind::Other, |
| 82 | + format!("Command failed: {:?}", cmd), |
| 83 | + )) |
| 84 | + } else { |
| 85 | + Ok(()) |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +fn main() -> std::io::Result<()> { |
| 90 | + // Stage dir for the embedded C project |
| 91 | + let mut dir = PathBuf::from("target/heresy_c"); |
| 92 | + fs::create_dir_all(&dir)?; |
| 93 | + |
| 94 | + // Write generator C file |
| 95 | + let gen_c = dir.join("heretic_build.c"); |
| 96 | + { |
| 97 | + let mut f = fs::File::create(&gen_c)?; |
| 98 | + f.write_all(C_GENERATOR.as_bytes())?; |
| 99 | + } |
| 100 | + |
| 101 | + // Compile the generator |
| 102 | + println!("🔧 compiling embedded C generator 👉 {}", gen_c.display()); |
| 103 | + sh(Command::new("gcc") |
| 104 | + .arg("-Wall").arg("-g").arg("-O0") |
| 105 | + .arg(gen_c.file_name().unwrap()) |
| 106 | + .arg("-o").arg("heretic_build") |
| 107 | + .current_dir(&dir))?; |
| 108 | + |
| 109 | + // Run the generator with recursion guard |
| 110 | + println!("🌀 running C generator…"); |
| 111 | + let mut run_gen = Command::new("./heretic_build"); |
| 112 | + run_gen.current_dir(&dir); |
| 113 | + run_gen.env("HERESY_ONCE", "1"); |
| 114 | + sh(&mut run_gen)?; |
| 115 | + |
| 116 | + // Show the result |
| 117 | + let exe = dir.join("heresy_exe"); |
| 118 | + println!("✅ generator produced: {}", exe.display()); |
| 119 | + |
| 120 | + // Demo run |
| 121 | + println!("▶️ executing heresy_exe:"); |
| 122 | + let out = Command::new(exe).output()?; |
| 123 | + print!("{}", String::from_utf8_lossy(&out.stdout)); |
| 124 | + eprint!("{}", String::from_utf8_lossy(&out.stderr)); |
| 125 | + |
| 126 | + println!("🎯 Done. Maximum C-in-Rust heresy achieved."); |
| 127 | + Ok(()) |
| 128 | +} |
0 commit comments