feat(windows): Delphi CE interactive build workflow#16044
Conversation
Lets developers on the free Delphi Community Edition tier build the still-Delphi parts of the tree, even though CE 11+ blocks the dcc32 CLI that build.sh normally drives. None of the compiler / runtime stack moves; this is purely build-environment work plus docs. CI is unchanged. KEYMAN_DELPHI_CE is unset by default, so build.sh keeps invoking msbuild.exe exactly as before. Depends on the Delphi 11/12 source-compat work in a sibling PR — that PR adds the VER350/VER360 IFDEF arms and KEYMAN_DELPHI_VERSION knob needed for the IDE to actually compile. Build-script knob: * resources/build/win/environment.inc.sh: delphi_msbuild() now checks KEYMAN_DELPHI_CE=1. When set, it prints an IDE-build prompt naming the .dproj and waits for Enter instead of running msbuild.exe. The pre-build (rc.exe) and post-build (binary copy, codegen) steps in build.sh run normally around the prompt, so the developer only has to drive the Delphi compile by hand. Docs: * docs/build/windows.md: one-line pointer to windows-delphi-ce.md from the existing "Delphi 10.3 CE no longer available" warning, so future CE users find the workaround instead of dead-ending. * docs/build/windows-delphi-ce.md: ~940-line guide -- prerequisites, registry library-path setup, source patches required on the sibling branch, the canonical build order (including the tsysinfox64 -> .bin -> tsysinfo_x64.res chicken-and-egg), install-and-overlay workflow, debugging, and a troubleshooting catalog. Written against Delphi 12 Athens CE specifically (currently the only free tier); Delphi 11 CE works with the same approach modulo a couple of paths. engine.groupproj fix (independent of the Delphi work but unblocks IDE "Build All", which CE users rely on): * windows/src/engine/engine.groupproj: drop the inst\insthelper reference. The path doesn't resolve -- insthelper.dproj lives at windows/src/engine/insthelper, not .../inst/insthelper -- and IDE "Build All" was failing on it. build.sh-based builds were never affected because they don't walk the groupproj. .gitignore: add patterns for the per-script log files that the CE workflow writes (configure.log, core-build.log, etc.). Relates-to: keymanapp#4599
User Test ResultsTest specification and instructions ERROR: user tests have not yet been defined |
|
This pull request is from an external repo and will not automatically be built. The build must still be passed before it can be merged. Ask one of the team members to make a manual build of this PR. |
|
Took a hard look at the groupproj-batching path. Sharing the analysis so we can pick the cheapest workable design. Coverage and order — what each groupproj would buy us on CE
So before any other consideration, adopting What
|
|
I had Claude plow through the build and tell me what to do every time I hit an error until I could compile and run everything. I hit all those A-F chicken/egg compile problems above trying to follow the build. I wonder if the CLI version would hit some of the same blockers if it was put onto a fresh new machine, but I can't test that (and don't want to start from scratch again while in "hackathon" mode. I only know it worked on my machine after all the intervening workarounds. |
mcdurdin
left a comment
There was a problem hiding this comment.
There's a lot of redundant and incorrect information in the docs. I think this needs a thorough rework
| * **Keyman 19 (official release)** installed from | ||
| https://keyman.com/desktop. This is *not* optional for Delphi 12 CE | ||
| developers -- the dev kmshell.exe runtime-discovers its install path via | ||
| `TKeymanPaths.KeymanDesktopInstallPath()`, which is hardcoded to | ||
| `C:\Program Files (x86)\Keyman\Keyman Desktop\`. Without the install, | ||
| kmshell crashes at startup with `SKApplicationTitle has had a fatal | ||
| error...` before its main form appears. See section 7 (Running). |
There was a problem hiding this comment.
This doesn't seem right; TKeymanPaths.KeymanDesktopInstallPath() does not hard code this path as it is read from the registry.
To run keyman.exe properly so that it can interact with elevated UI processes (uiAccess=true in the manifest), it needs to be signed with a valid cert, and be installed in a hardened path such as Program Files. But for debugging, you can run keyman.exe unsigned with uiAccess=false, in non-elevated processes. All other components should be runnable outside of Program Files, although there are libraries that have to be located.
| installed Developer support files. | ||
| * **7-Zip** (`choco install 7zip`) for extracting the CEF libcef payload. | ||
|
|
||
| ## 2. One-time setup |
There was a problem hiding this comment.
Most of this section should be in windows.md and if that file is not correct, should be corrected; it's best not to duplicate.
| `common/windows/cef-checkout.sh` normally does this, but if you're driving | ||
| Delphi from the IDE you'll want to do it once by hand. Some payload files | ||
| exceed GitHub's 100 MB limit and ship as `.zip` files inside the repo; they | ||
| must be extracted in place. |
There was a problem hiding this comment.
Why? This doesn't require any Delphi bits in order to be checked out.
| ### 2.6 Install Keyman 19 official | ||
|
|
||
| Install Keyman 19.0 from https://keyman.com/desktop. After install verify | ||
| `C:\Program Files (x86)\Keyman\Keyman Desktop\kmshell.exe` exists and that | ||
| `HKLM\SOFTWARE\WOW6432Node\Keyman\Keyman Engine` is populated. The overlay | ||
| workflow in section 7 depends on these. |
There was a problem hiding this comment.
This is not right. keyman.com/windows. s/overlay/debugging. The reason for installing Keyman is to simplify the install environment but it is possible to debug without Keyman installed.
| ```powershell | ||
| # Elevated PowerShell -- back up first | ||
| reg export 'HKCU\Software\Embarcadero\BDS\23.0\Library' ` | ||
| C:\Projects\keyman\keyman\delphi-library-paths.backup.reg /y | ||
|
|
||
| $key32 = 'HKCU:\Software\Embarcadero\BDS\23.0\Library\Win32' | ||
| $key64 = 'HKCU:\Software\Embarcadero\BDS\23.0\Library\Win64' | ||
|
|
||
| $paths = @( | ||
| # Keyman common includes (mirrors DELPHIINCLUDES in delphi_flags.inc.sh) | ||
| 'C:\Projects\keyman\keyman\common\windows\delphi\ext\cef4delphi\source', | ||
| 'C:\Projects\keyman\keyman\common\windows\delphi\ext\dcpcrypt', | ||
| 'C:\Projects\keyman\keyman\common\windows\delphi\ext\jwa\Win32API', | ||
| 'C:\Projects\keyman\keyman\common\windows\delphi\ext\sentry', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\mbcolor', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\scfontcombobox', | ||
| # JCL / JVCL source roots (needed for TIKE) | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jcl\jcl\source\common', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jcl\jcl\source\prototypes', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jcl\jcl\source\vcl', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jcl\jcl\source\windows', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jcl\jcl\source\include', # jcl.inc | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jvcl\jvcl\design', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jvcl\jvcl\run', | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jvcl\jvcl\common', # jvcl.inc | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jvcl\jvcl\resources', # JvConsts.res | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi\jedi', # jedi.inc | ||
| 'C:\Projects\keyman\keyman\developer\src\ext\jedi' # parent for {$I jedi\jedi.inc} | ||
| ) | ||
|
|
||
| foreach ($key in @($key32, $key64)) { | ||
| $cur = (Get-ItemProperty -Path $key -Name 'Search Path' ` | ||
| -ErrorAction SilentlyContinue).'Search Path' | ||
| $merged = (@($cur -split ';') + $paths | | ||
| Where-Object { $_ } | | ||
| Select-Object -Unique) -join ';' | ||
| Set-ItemProperty -Path $key -Name 'Search Path' -Value $merged | ||
| } | ||
| ``` |
There was a problem hiding this comment.
This is fragile because if we make changes to the project the docs will need to be updated so we don't get out of sync. I don't like having this kind of thing twice really.
| ### `E2010 Incompatible types: 'Cardinal' and 'Boolean'` (JCL) | ||
|
|
||
| JCL Boolean -> BOOL casts missing. See section 3.4. | ||
|
|
||
| ### `E2003 Undeclared identifier: 'OldCreateOrder'` (JVCL) | ||
|
|
||
| JvComponent.pas not patched. See section 3.5. | ||
|
|
||
| ### `E2003 Undeclared identifier: 'null'` (HTMLColors) | ||
|
|
||
| mbcolor's `mxs.inc` not patched for VER350/VER360 -- the `Variants` unit | ||
| was silently dropped from the `uses` clause. See section 3.6. | ||
|
|
||
| ### `E2029 Declaration expected` near SourceRootPath.pas | ||
|
|
||
| devtools/SourceRootPath.pas hit the `{$ELSE} {$MESSAGE ERROR}` fallback. | ||
| See section 3.7. | ||
|
|
||
| ### `E2012 Type of expression must be BOOLEAN` near EnumFontFamiliesEx | ||
|
|
||
| CleartypeDrawCharacter.pas guard not extended for VER350/VER360. See | ||
| section 3.10. |
| ### `SKApplicationTitle has had a fatal error...` on kmshell launch | ||
|
|
||
| kmshell can't find its strings.xml / locale files because | ||
| `KeymanDesktopInstallPath()` is hardcoded to `Program Files`, and Keyman | ||
| 19 official isn't installed (or its install support files were removed by | ||
| an aborted dev experiment). Install Keyman 19 official from keyman.com. |
There was a problem hiding this comment.
hmm don't think this is correct diagnosis
|
|
||
| --- | ||
|
|
||
| ## Upstream candidates |
| These should *not* be PR'd upstream-Keyman as-is; the bundled third-party | ||
| copies should be refreshed from their respective maintainers instead. | ||
|
|
||
| ## Reverting before a PR |
| # Local artifacts from the Delphi CE dev workflow (see docs/build/windows-delphi-ce.md) | ||
| /delphi-library-paths.backup*.reg | ||
| /local-delphi-12-patches.patch | ||
| /configure.log | ||
| /core-build.log | ||
| /cpp-engine-build.log | ||
| /install-build-env.log | ||
| /kmcmplib-build.log | ||
| /web-build.log |
There was a problem hiding this comment.
I really don't know where these files come from. They do not seem to be generated
Summary
Lets developers on the free Delphi Community Edition tier build the still-Delphi parts of the tree, even though CE 11+ deliberately blocks the
dcc32CLI thatbuild.shnormally drives. None of the compiler / runtime stack moves; this is purely build-environment work plus docs.CI is unchanged.
KEYMAN_DELPHI_CEis unset by default, sobuild.shkeeps invokingmsbuild.exeexactly as before.Split off from #16039 per @mcdurdin's review — that PR bundled the CE workflow with the Delphi 11/12 source-compat patches. This PR is the CE half; the compat half is #16043.
Depends on #16043 for the source-compat patches and the
KEYMAN_DELPHI_VERSIONknob that lets the IDE find Delphi 11/12.Why this matters for the Delphi removal roadmap
Delphi 10.3 Pro is no longer obtainable, and CE 10.3 has been removed from Embarcadero's downloads. New contributors who want to help finish #4599 currently hit a wall: they can install CE 12, but CE blocks
dcc32andbuild.shfalls over before reaching any Delphi project. This PR fixes the wall — without committing to keep Delphi alive.What's in the change
1. CE-aware
delphi_msbuildresources/build/win/environment.inc.sh:delphi_msbuild()now checksKEYMAN_DELPHI_CE. When=1, it prints an IDE-build prompt naming the.dprojand waits for Enter instead of invokingmsbuild.exe. The pre-build (rc.exe, manifest gen) and post-build (binary copy, codegen) steps inbuild.shrun normally around the prompt, so the developer only has to drive the Delphi compile by hand.This is the approach @mcdurdin proposed in #16039 (comment) — gate by version in the existing shell script rather than parallel PowerShell helpers.
2. Docs
docs/build/windows.md: one-line pointer towindows-delphi-ce.mdfrom the existing "Delphi 10.3 CE no longer available" warning, so future CE users find the workaround instead of dead-ending.docs/build/windows-delphi-ce.md: ~940-line guide — prerequisites, registry library-path setup, source patches required on chore(windows): Delphi 11/12 source compatibility #16043, the canonical build order (including thetsysinfox64->.bin->tsysinfo_x64.reschicken-and-egg), install-and-overlay workflow, debugging, troubleshooting catalog, and a section labeling which patches are safe to upstream. Written against Delphi 12 Athens CE specifically (currently the only free tier); Delphi 11 CE works with the same approach modulo a couple of paths.3.
engine.groupprojfixwindows/src/engine/engine.groupproj: drop theinst\insthelperreference. The path doesn't resolve —insthelper.dprojlives atwindows/src/engine/insthelper, not.../inst/insthelper— and IDE "Build All" was failing on it.build.sh-based builds were never affected because they don't walk the groupproj.Technically independent of the CE work, but bundled here because IDE "Build All" is the path CE users actually exercise. Happy to split into its own PR if reviewers prefer.
4.
.gitignorePatterns for the per-script log files that the CE workflow writes (
configure.log,core-build.log, etc.).Reviewer notes
if [[ "${KEYMAN_DELPHI_CE:-}" == "1" ]]branch indelphi_msbuild(). Everything else is docs / .gitignore / the orthogonalengine.groupprojcleanup.KEYMAN_DELPHI_CE=1 ./build.sh.windows-delphi-ce.md(notwindows-d12.md) so the same workflow guide applies if/when a future Delphi 11 CE user shows up; the body is Delphi 12-specific because that's what's been actually tested.User Testing
User testing not required: build-environment / docs change with no runtime behaviour modification. CI will exercise the non-CE default path (
KEYMAN_DELPHI_CEunset); the CE flow is manually validated via the steps indocs/build/windows-delphi-ce.md.Relates-to
Relates-to: #4599
Depends-on: #16043
Replaces: #16039 (split into #16043 + this PR)