1. i can compile again thanks to AI
- Posted by euphoric (admin) 1 week ago
- 181 views
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
2. Re: i can compile again thanks to AI
- Posted by Lnettnay 6 days ago
- 217 views
Inquiring minds want to know. What was going wrong?
Lonny
3. Re: i can compile again thanks to AI
- Posted by euphoric (admin) 5 days ago
- 151 views
Inquiring minds want to know. What was going wrong?
Lonny
I knew someone was going to ask that.
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.
4. Re: i can compile again thanks to AI
- Posted by petelomax 5 days ago
- 125 views
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!

