Retiring the Makefile and make.ps1 #5588
Replies: 4 comments
-
|
The install changes in #5620 — namespacing ponyc's headers under Reproduce the new header layout. ponyc's shim-facing headers install under Don't reintroduce the runtime-embedding surface. The runtime headers and The upgrade cleanup moves over too. The Makefile removes the stale flat symlinks an older install left in the shared dirs. That should move into the CMake install and stay for a while — until installs with the old layout are gone — then come out. It's what cleans up after someone who upgrades from a pre-namespace ponyc straight across the Makefile's retirement. |
Beta Was this translation helpful? Give feedback.
-
|
Did the groundwork reading before starting phase 1. Three things turned up worth writing down. None of them change a decision; two pin down where logic has to land, and the third is progress on verifying the floor bump. The Compiler selection has to reach the libs build, not just ponyc. Floor bump, on the verification. Linux is good. Every Linux builder is well above 3.25: Ubuntu 24.04 is 3.28, and Alpine 3.23/3.24, Arch, Fedora 44, and Ubuntu 26.04 are all newer than that. The cross builders inherit the Ubuntu 24.04 image, so they're covered too, and the GitHub macOS and Windows runners are well past 3.25. The BSDs I have not actually checked. FreeBSD 15.1, OpenBSD 7.9, and DragonFly 6.4.2 install cmake from |
Beta Was this translation helpful? Give feedback.
-
|
Comment from me in the sync call:
|
Beta Was this translation helpful? Give feedback.
-
|
Groundwork is up as #5633: the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
ponyc gets built three ways. There's a
Makefile, there's amake.ps1, and there's the CMake project both of them call. CMake does the actual work. The Makefile andmake.ps1are supposed to be thin convenience wrappers sitting in front of it.They aren't thin. Each one carries real build logic, and the same logic gets written twice, once in Make and once in PowerShell, and kept in sync by hand. Hand-syncing logic across two files in two languages is about as reliable as it sounds. That's where a string of our build-system bugs has come from.
Look at what the wrappers carry. They turn
config=debug use=address_sanitizerinto the CMake flags that mean it. They reject build options that don't work on a given platform, up front, with a clear error instead of a confusing failure partway through the build. They find the build output directory after the fact by grepping a file CMake generated, because the directory name changes with the options you turned on. The Makefile, on top of that, tracks which Pony source files changed so the right tool binaries rebuild. Most of this is written twice, once in Make and once in PowerShell, and the two copies get kept in line by hand.When the same logic lives in two hand-maintained files, the two drift, and the drift is what bites you. The Makefile supports more than a dozen
use=build options;make.ps1supports exactly one,systematic_testing, and rejects the rest with a hard error, so the options the Makefile grew over the years never came to Windows.make installis hand-written and separate from CMake, so it never uses the CPU architecture you configured with. Configure for a non-default architecture, build, then runmake installwithout repeating the architecture, and the runtime libraries land in the directory for the default one, where the installed compiler won't find them. That's #3898. Thepony-lintbinary gets built two ways, once by CMake for the installed tool and once by a separate hand-written rule for CI, the same job done twice and drifting apart. Different symptoms, same root cause: logic that belongs in CMake is living in a wrapper instead, and a wrapper can't carry that logic for two platforms without the copies coming apart. #5282 is the running list of these.So the fix isn't "delete two files." It's move every piece of that logic into the one place both platforms already share, the CMake project, until the wrappers hold nothing worth keeping. Then delete them.
Where this lands
At the top of the tree, two files:
CMakeLists.txtfor the build,CMakePresets.jsonfor the knobs. No hand-writtenMakefile, nomake.ps1.You build with one command that runs the same on Linux, macOS, Windows, and the BSDs:
That configures, builds, and tests in one shot. The long
use=...strings become named presets, so the sanitizer build that today ismake configure config=debug use=pool_memalign,address_sanitizer,undefined_behavior_sanitizer && make build config=debugbecomescmake --workflow --preset debug-asan. Tests run throughctest, the same on every platform, selected by label:ctest --preset debug -L ci-coreruns the core CI suite. Install iscmake --install, and because it reads the architecture out of the cache CMake writes at configure time instead of a re-typed argument, the #3898 install bug stops being possible.CMake is a build-system generator. It already generates a
build.ninja(or a Makefile) underbuild/and uses that for the real work. That generated file isn't the hand-writtenMakefileat the top of the tree, and it regenerates whenever a CMake input changes, as part of the build you were already running. Nobody edits it. Nobody keeps it in sync with anything.Why no wrapper, even a thin one
The objection is to keep a thin wrapper so the short commands still work. I went back and forth on this and landed on no wrapper at all.
A wrapper is worth keeping only if it carries something. A wrapper that just forwards
debugtocmake --workflow --preset debugcarries nothing you couldn't get by typing the cmake command. A wrapper that does more than forward now carries its own list of build options, and that list drifts from the presets the same way the Makefile andmake.ps1drift from each other today. The first kind has no value. The second kind is the thing we're removing. There's no third kind worth having, so the wrapper goes.The two pieces that take real design
Most of this is moving logic from one place to another. Two pieces are actual design work.
The first is a small CMake helper for compiling Pony binaries. The tool binaries (
pony-lint,pony-lsp,pony-doc) are already built inside CMake by invoking the just-builtponycon their source. The five binaries the Makefile hand-rolls (pony-lint-ciand the fourpony-*-tests) are built the same way, just outside CMake, with their dependency tracking written by hand. The helper extracts the pattern that already exists into one function so both the tools and the test binaries go through a single dependency-tracking path instead of CMake's for one and a hand-rolled copy for the other.The second is the preset layout: a preset per build configuration, presets that layer the
use=options on top, presets for the cross-compile targets, and a separate preset for the LLVM libraries. The test groups we run today (test-ci-core, the tool test suites, the stress runs) becomectestlabels you select with-L. The catch is thatctestregistration is new work. We don't usectestat all today, so every test runner, including the ones that compile a program withponycand then run it, has to be wired up from scratch. That is the largest single chunk of the migration, and it's the part most likely to surface surprises.The plan
The work goes in phases. Each one stands on its own, ships on its own, and removes logic rather than adding a second copy of it, so the duplication only ever shrinks. There's never a point where three things have to be kept in sync.
use=validation and the clang/compiler selection out of the wrappers and into CMake. AddCMakePresets.json. Bump the required CMake version to 3.25 (more on that below). Nothing gets deleted; CI keeps running as-is. The presets get exercised before anything depends on them.pony-lint-ci. Point the lint steps at thepony-lintbinary CMake already builds. One whole hand-rolled binary and its custom dependency tracking go away. This is the smallest piece and it lands first.pony-*-tests. The Makefile's hand-rolled build graph and its order-only edges are deleted here.test-*targets become labels. Themake.ps1test machinery is retired.Decisions already made
A few choices are settled, with reasons, so we can start from them instead of relitigating them.
The CMake floor goes to 3.25. The one-command
cmake --workflowform needs CMake 3.25. The configure/build/test presets underneath it only need 3.20, which is below our current 3.21 floor, so the floor bump buys the single-command convenience and nothing else. The cost is real: every CI builder image and every BSD VM has to ship CMake 3.25 or newer. Building the LLVM libraries with CMake today only proves an image has 3.21, not 3.25, so this is a thing to verify image by image and upgrade where it's short, not an assumption.No wrapper. Delete the Makefile and
make.ps1, type cmake directly.Windows runs tests the same way as everywhere else. Today Windows selects tests by name through
make.ps1, with its own set of names that don't match the Unix targets. After this, every platform runsctest -L <label>. Unifying it is the whole point; the cost is that the Windows CI test steps get rewritten rather than translated.Release packaging stays a thin archive step, not CPack. The released tarball and zip have to stay exactly what they are today, same layout and same names, because ponyup and the rest of the ecosystem depend on it. The current packaging is a
tar(orCompress-Archive) of the install tree. Keeping that exact step, run over whatcmake --installproduces instead of whatmake installproduces, gives an identical result by construction. CPack would wrap the contents in a top-level folder and rename the archive by default, so matching today's output would mean configuring CPack until it stops doing that and then diffing every release to be sure. The plain archive has none of that risk.No examples in either package. The Windows zip ships
examples/today and the Unix tarball doesn't. Rather than make them match by shipping examples everywhere, they match by shipping examples nowhere.Out of scope
Two build options,
ltoandruntime-bitcode, aren't exercised in CI but are real documented options, and the Makefile is the only way to set them today. They need preset equivalents or an explicit decision to drop them before the Makefile goes. A couple of older build-system issues (#3467, #3466) fall out of this work naturally and can be folded in or tracked separately. #3536, the compiler path getting hardcoded into the binary, is untouched by any of this and stays its own conversation.That's the shape of it. The wrappers were never supposed to hold a build graph. They grew one, and the fix is to give it back to CMake and let the wrappers go.
Beta Was this translation helpful? Give feedback.
All reactions