1. i can compile again thanks to AI

Just want to say that for years I have not been able to compile my wxEuphoria app.

I asked AI to help me resolve it, and it did, within 10 minutes or so.

I'm back to compiling my app for distribution instead of just binding it.

AI-1, Humans-0

grin

new topic     » topic index » view message » categorize

2. Re: i can compile again thanks to AI

Inquiring minds want to know. What was going wrong?

Lonny

new topic     » goto parent     » topic index » view message » categorize

3. Re: i can compile again thanks to AI

Lnettnay said...

Inquiring minds want to know. What was going wrong?

Lonny

I knew someone was going to ask that. grin

I cannot confirm or deny any of the claims made below. This is what was derived from the git repo.

# Compiling Euphoria apps with euc: what breaks and how to fix it 
 
A write-up of the problems encountered moving a wxEuphoria desktop app from 
`eubind` to `euc` (native compile), and the fixes that made the compiled build 
work. Posting this because the failure modes were subtle - the crash symptoms 
rarely pointed at the actual cause. 
 
--- 
 
## Background 
 
Euphoria apps can be built two ways: 
 
- **Bind mode** (`eubind`): packages the interpreter + bytecode into a standalone `.exe`. 
- **Compile mode** (`euc`): translates Euphoria source to C, then compiles the C with `mingw32-make` into native machine code. 
 
The two are **not** behaviorally identical. For a long time this project could 
only be built in bind mode; the compile path was abandoned. The differences 
below are what made compilation viable. 
 
--- 
 
## Problem 1: Forward references that the interpreter tolerates but euc doesn't 
 
**Symptom:** The compiled `.exe` crashed on startup. The crash surfaced deep 
inside an unrelated wxWidgets call (`wxImage::AddHandler`), hiding the real cause. 
 
**Cause:** A top-level statement called a routine (`version_string()`) that was 
defined in an `include` file which appeared *later* in the file. 
 
- The interpreter and `eubind` resolve symbols in multiple passes, so this 
  forward reference works fine at runtime. 
- `euc` translates to C that executes top-level statements in **strict textual 
  order**. The translated C jumped into a routine that hadn't been initialized 
  yet. 
 
**Fix:** Move the `include` **above** the first use. Specifically, `include 
foadman.e` needed to appear before the `progDlg` creation that called 
`version_string()`. 
 
**Rule of thumb:** Anything referenced from a top-level statement must be 
`include`d before that statement. Don't rely on interpreter-style forward 
reference resolution. 
 
--- 
 
## Problem 2: euc constant-folds type guards away 
 
**Symptom:** Fatal error `"second argument of find/find_from() must be a 
sequence"` on machines where a particular registry key didn't exist. 
 
**Cause:** The `euc` translator does **not** type-check parameters, and it 
**constant-folds `atom()` on a `sequence`-declared variable to `FALSE`**. So 
this guard: 
 
```euphoria 
function f(sequence key) 
    if atom(key) then return {} end if 
    ... 
``` 
 
...was **deleted from the compiled exe** entirely. When the callee returned an 
error code (an atom), `find()` received an atom and crashed. 
 
**Fix:** Declare the parameter as `object`, not `sequence`, whenever the callee 
can legitimately return an atom (e.g. an error code): 
 
```euphoria 
function f(object key) 
    if atom(key) then return {} end if 
    ... 
``` 
 
**Same applies to local variables.** If you write `if not sequence(x) then` 
to defend against a function returning an error atom, but `x` is declared as 
`sequence`, the check gets compiled away. Declare it as `object`. 
 
--- 
 
## Problem 3: Registry access works interpreted, fails compiled 
 
**Symptom:** `regGetSubkeys(HKLM\SOFTWARE\Microsoft\Office)` returned an error 
when run from the compiled exe, but worked fine when run interpreted. 
 
**Cause:** The registry-open code always requested `KEY_ALL_ACCESS`. A 
**non-elevated compiled exe is denied that on HKLM** (`ERROR_ACCESS_DENIED`). 
 
**Fix:** Use `KEY_READ` (`#20019` = `STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | 
KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY`) for read-only operations. Keep 
`KEY_ALL_ACCESS` only for writes. Give `openKey()` an optional access-mask 
parameter and pass the right one per call. 
 
--- 
 
## Problem 4: Heap buffer overrun in a Windows API wrapper 
 
**Symptom:** None directly - latent memory corruption. 
 
**Cause:** `RegEnumKeyExA` writes an 8-byte `FILETIME`, but the wrapper 
allocated only 4 bytes for the output buffer. 
 
**Fix:** Allocate 8 bytes for `FILETIME` buffers. (Note: this kind of bug can 
manifest differently under compiled vs. interpreted builds because the memory 
layout differs.) 
 
--- 
 
## Problem 5: Raw machine-code injection doesn't translate 
 
**Symptom:** Compile fails or behaves unpredictably for code that injects and 
calls raw machine code. 
 
**Cause:** `euc` translates to C; raw machine-code stubs have no C equivalent. 
 
**Fix:** Rewrite such routines in pure Euphoria (e.g. CRC32 can be done 
entirely in Euphoria without machine-code tricks). 
 
--- 
 
## Problem 6: euc writes translation errors to a file, not the console 
 
**Symptom:** `euc` exits with an error but prints nothing useful. 
 
**Cause:** `euc` silently writes unresolved-reference and translation errors to 
`ex.err` instead of the console. 
 
**Fix:** After running `euc`, check for `ex.err` and print it. Always. 
 
--- 
 
## Problem 7: Newly-linked exe can be locked by antivirus 
 
**Symptom:** The final `move` / `rename` of the compiled exe fails immediately 
after linking. 
 
**Cause:** Real-time antivirus scanning transiently locks freshly-written 
executables. 
 
**Fix:** Retry the move a few times with a short delay before giving up. 
 
--- 
 
## Problem 8: wxEuphoria bugs that manifest only in compiled builds 
 
`get_next_tree_child()` (wxTreeCtrl wrapper) never actually returns the next 
child - it loops forever or returns the same child. This was observed under the 
compiled build. 
 
**Fix:** Don't rely on tree-walking to enumerate children. Keep the underlying 
data (e.g. a list of forms) in memory and iterate that instead. 
 
--- 
 
## Build-script hardening 
 
`_make_exe.bat` was rewritten with two modes and real error checking: 
 
- `bind` mode: `eubind` (fast, always worked). 
- `compile` mode: `euc` translate -> `windres` generate `.res` -> `mingw32-make`. 
- `windres` must run to generate the `.res` file (this step was previously 
  never run). 
- Check `errorlevel` after every step. 
- Check for `ex.err` after `euc` (see Problem 6). 
- Retry the final exe `move` for antivirus locking (see Problem 7). 
- Delete the `build\` directory only on a fully successful compile; leave it in 
  place on failure for debugging. 
 
Additionally, debug logging should flush after every write, so the log survives 
a native crash instead of losing its buffered tail. 
 
--- 
 
## Summary 
 
| # | Problem | Cause | Fix | 
|---|---|---|---| 
| 1 | Compiled exe crashes on startup | Forward reference; euc runs top-level statements in textual order | Move `include` above first use | 
| 2 | `find()` receives an atom | euc constant-folds `atom()` guard away on `sequence`-declared variables | Declare params/vars as `object` | 
| 3 | Registry read fails compiled | `KEY_ALL_ACCESS` denied on HKLM for non-elevated exe | Use `KEY_READ` for reads | 
| 4 | Latent heap overrun | `FILETIME` buffer allocated 4 bytes instead of 8 | Allocate 8 bytes | 
| 5 | Machine-code injection won't compile | No C equivalent for raw machine code | Rewrite in pure Euphoria | 
| 6 | euc "succeeds" but nothing useful prints | Errors go to `ex.err`, not the console | Check and print `ex.err` | 
| 7 | Final exe `move` fails | Antivirus transiently locks fresh exe | Retry with delay | 
| 8 | Tree enumeration broken compiled | wxEuphoria `get_next_tree_child()` bug | Keep data in memory, don't walk the tree | 
 
The biggest general lesson: **`euc` is not a drop-in replacement for 
`eubind`.** The translator makes different assumptions (strict top-level 
ordering, constant-folding of type checks) than the interpreter. Code that 
works interpreted can silently lose its defensive checks when compiled. Prefer 
`object` over `sequence` whenever a value can legitimately be an atom (e.g. an 
error code), and put every `include` above its first use in top-level code. 
 
--- 
 
## Attribution: whose bug was it anyway? 
 
For the benefit of anyone wondering which problems are worth reporting 
upstream versus just fixing in their own code: 
 
**App-code bugs that the interpreter masked:** 
- Forward reference to a routine used in a top-level statement (Problem 1). 
  Real mistake in the app code, but the interpreter's multi-pass resolution 
  hides it and euc exposes it. 
- `atom()` guard on a `sequence`-declared variable (Problem 2). The mistake is 
  natural; the silent punishment is the problem. 
- Using `KEY_ALL_ACCESS` for read-only registry access (Problem 3). A latent 
  bug regardless of build mode; it just happens to be masked when running 
  elevated. 
- Undersized `FILETIME` buffer (Problem 4). A plain Windows API mistake. 
- Raw machine-code injection (Problem 5). A fragile technique that has no C 
  equivalent and can't survive translation. 
 
**Euphoria / `euc` design issues worth reporting or at least being aware of:** 
- `euc` constant-folds `atom()` on a `sequence`-declared variable to `FALSE` 
  instead of type-checking the parameter. This is the single most dangerous 
  divergence between the interpreter and the compiler - defensive checks 
  silently disappear from the compiled build. 
- `euc` runs top-level statements in strict textual order while the 
  interpreter resolves symbols multi-pass. The divergence is the root cause of 
  Problem 1 and is easy to miss. 
- `euc` writes translation errors to `ex.err` instead of stderr / the console 
  (Problem 6). Poor DX; the build should fail loudly. 
 
**Windows / environment realities (not a bug anywhere):** 
- Antivirus real-time scanning transiently locks freshly-linked executables 
  (Problem 7). 
 
**wxEuphoria / wxWidgets bug:** 
- `get_next_tree_child()` never actually returns the next tree child. This is 
  a genuine wxEuphoria bug, not a usage error. It surfaces more clearly under 
  the compiled workflow. The workaround is to keep the underlying data in 
  memory and iterate that instead of walking the tree. 
 
**Net:** Most issues were latent bugs in the app code that the interpreter 
masked, exposed by `euc`'s stricter translation. The one true external bug is 
wxEuphoria's `get_next_tree_child()`. The `euc` translator's silent 
constant-folding and silent `ex.err` are Euphoria design issues worth 
mentioning upstream. 
 

new topic     » goto parent     » topic index » view message » categorize

4. Re: i can compile again thanks to AI

Super impressive, innit? Just remember not to grant it super-powers it don't have: all that information was sitting ready and waiting for it, probably right here on Euforum[1].
Coincidentally, after at least 7 years I've just got it to help me build Lite[Un]Zip.(32|64).dll - cmake/Visual studio 2022 took 2 whole days, when I then asked it to try
gcc instead, that was finished in under 4 hours (admittedly w/o having to re-apply the 5 or 10 source code tweaks already in place for 64 bit support/compilation).

[1] eg https://openeuphoria.org/forum/132868.wc#132868 - so I can't say whether it actually needed that, but it works, so who cares!

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu