-
Notifications
You must be signed in to change notification settings - Fork 381
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[ build ] A major refactor of the build system #1990
[ build ] A major refactor of the build system #1990
Conversation
2b1d222
to
b5146c8
Compare
I've been working on switching to Miscellaneous comments: Add ".mk" extension to fix syntax highlighting in GitHub. Should add quotes when doing You can use
In theory you could build only the modules imported by the compiler for the first stage(s). I'm not sure if it is worth the complexity, but it would trim some bootstrap time. Trick to skip bytecode compilation: Some snippets
cygpath = $(and $1, $(if $(isWindows), $(shell cygpath -m $2 "$1"), $(abspath $1))
IDRIS2_PATH := $(TARGETDIR)/$(subst $= ,/build/ttc:$(TARGETDIR)/,$(wildcard libs/*))/build/ttc
IDRIS2_PATH := $(call cygpath, $(IDRIS2_PATH), --path)
# Use support files without installing for every stage
IDRIS2_DATA := $(call cygpath, $(TARGETDIR)/support)
IDRIS2_LIBS := $(call cygpath, $(TARGETDIR)/support/c) You could use #!/bin/sh
BOOTDIR=$(cd -P "$(dirname "$0" && pwd)"
export LD_LIBRARY_PATH=$BOOTPATH/lib:$LD_LIBRARY_PATH
if [ -n "$OS" ] && [ -z "${OS##*_NT*}" ] || [ "$OS" = windows ]; then
PATH=$BOOTPATH/lib:$PATH
fi
if [ "$IDRIS2_CG" = racket ]; then
"${RACKET-racket}" "$DIR/bin/compiled/idris2_rkt.zo" "$@"
elif [ -n "$SCHEME" ]; then
"$SCHEME" --script "$BOOTDIR/bin/idris2.so" "$@"
else
echo 'idris2.sh - Usage:' >&2
echo 'SCHEME=<chez-scheme> idris2.sh' >&2
echo 'IDRIS2_CG=racket idris2.sh' >&2
exit 1
fi idris2-paths:
printf %s\\n \
"-- @""generated" \
"module IdrisPaths" "" \
"export" \
"idrisVersion : ((Nat,Nat,Nat), String)" \
"idrisVersion = (($(MAJOR),$(MINOR),$(PATCH)), \"$(VERSION_TAG)\")" "" \
"export" \
"yprefix : String" \
"yprefix = \"$(PREFIX)\"" > src/IdrisPaths.idr It's better than the old one, just. It'd be nice to shove it in a file instead. Maybe: IdrisPaths:
sed \
"s|([0-9,]*), \"\"|($(MAJOR),$(MINOR),$(PATCH)), \"$(GIT_SHA1)\"|" \
"s|__PREFIX__|$(IDRIS2_PREFIX)|" \
IdrisPaths.template > build/paths.idr
if ! cmp -s build/paths.idr src/IdrisPaths.idr; then \
mv build/paths.idr src/IdrisPaths.idr; \
fi You don't need FORCE if you don't use the file's path for the target. From my custom.mk — maybe interesting, maybe not: quick: idris2-exec libs
quick: export IDRIS2_BOOT := $(CURDIR)/build/exec/idris2
run: ; IDRIS2_PREFIX=$(CURDIR)/build IDRIS2_PATH=$(IDRIS2_BOOT_PATH) ./build/exec/idris2 $(ARGS)
libs/*: ; $(MAKE) run ARGS+='--build $@/$(@F).ipkg'
.PHONY: $(wildcard libs/*)
version: run
version: ARGS = --version
mostlyclean: ; $(RM) -r build/ttc libs/*/build/ttc |
b5146c8
to
3ef2e5e
Compare
i was hoping that we could get rid of but reading you makes me think... shall i give up that pursuit as not feasible/desirable?
bah, of course. done. thanks!
you probably have reviewed an earlier state. i ran a phase of testing where the checkout dir is in a parent dir that contained spaces, and i have fixed several issues. this above being one of them. in the current revision i have undone the change that puts the CG's name in the output file's name as file extension. that was only necessary when i was defining every backend's rule unconditionally. now that i had to add conditional definition of the relevant rules to the makefile, i can manage with the standard file extensions, so i reverted that part to keep it all simpler.
makes sense, i have switched entirely to re
i'm keeping an eye on supporting make -j parallelism, and merging the rules serializes their compilation (unless there's some makefile magic to pralellize the shell commands of a rule). i'm not sure about this all, though.
hrm. how about renaming it to any suggestions for a better name for the test lib than either way, i'll do that in a separate commit/PR afterwards.
i don't get what you are referring to here.
in a future commit... :) this is extensive enough already.
oh, nice trick! :) unfortunately, i'm also trying to get away with the discrepancy between racket and the .so output of chez, and between their different wrapper scripts, and also of the fact that the wrapper script needs SCHEME to be defined. this is part of the in-place bootstrap shortcuts, so that the wrapper script can be the same for both CG's. when i employ this trick, it gets to the wrong place, i.e. into the shell line:
i hacked this away with some more as for an eventual merging of this PR: @benhormann, do you have the commit bit? if you do, then how about you fetch this PR locally (when i consider it done/tested), and then you fix/reshape anything you see, and then push both commits to main? judging from your comment you seem to be much more experienced with make than i am. i keep finding myself websearching for basic makefile stuff... |
Alpine Linux uses BusyBox, then there's BSD and macOS (generally the worst offender). It varies.
Ah, you'll could try
No, but I could help tidy it up in your branch. |
da61358
to
2140982
Compare
Check out benhormann:refactor-make-1, it's more of a refactor and less of a new system. Even if a new system is preferred, there are some decent ideas:
It's based off other work, so the CI has more Racket jobs. And re-enables tests on Windows. How about a './configure' script? A fairly simple script to handle things like OS specifics, Chez vs Racket, etc. It would populate config.mk with every option that stays consistent between builds. The version string would still require invoking git each build. Could skip it for many cases by assuming Linux/BSD defaults. (Could even make it easier to support BSD Make...) It would avoid having to do things like: |
FTR, the there are bug reports to Idris itself that suggests that it may be an Idris compiler bug (see e.g. #1974 or #2366), or i'm miscompiling Chez itself, or compile it in an incompatible way with the C side of Idris. the CI file suggests that it's all compiled using Mingw on Windows (e.g. it uses
good stuff! i should incorporate those, but this PR is already turning into a never ending story... :) as for a |
There is a windows installer for Chez, I'd use that version (pity it is awkward to install for CI).
Seems MinGW is the only working option.
I don't mean autoconf, a handwritten shell script will do. Question is if that is OK or not wanted. |
I don't understand this error, I build Chez on Windows with MSYS2 without any modifications, other than those I have submitted upstream to Chez. It should work as well with ordinary MSYS, as in the one that comes with Git for Windows, but I don't do that. Oh wait, maybe it's because the CI and I are using the Microsoft compiler to build it. I have built it using GCC in the past. But that was a while ago.
|
sorry for the confusion: Chez does build/work on both MSYS and Cygwin, but Idris itself doesn't build on Cygwin (fails at link time with a few missing symbol errors). (Further edited to clarify) |
when i try to use the binary install of chez, i get this:
even though
but it's not in
i have very little experience coding on windows... but maybe it's because the if i add it by hand:
then it just moves the goalpost to some moar pain:
|
csv956.dll would normally be in "C:\Program Files\Chez Scheme 9.5.6\bin\ti3nt". I just install Chez and the vc_redist, then add Chez to PATH. Seems like you already have the VC Redist. There is a way to configure it to inherit PATH but you shouldn't need to. IIRC, the CI uses that setting to locate Comparing the logs between ubuntu and windows, it looks equivalent up to I'd stop silencing commands with @, at least until it is all working. Prepending Eventually you'll discover |
ba4d498
to
201356a
Compare
Also use #!/usr/bin/env sh to be more accommodating to NixOS and Guix.
Please find the detailed description of this refactor in the form of an upcoming commit extending the documentation with a chapter on the build system. * Eliminates everything bootstrap related beyond the two Makefiles. * Adds a 'make release' target. * Eliminates several sub makefiles from subdirs. * Uses the $() convention in makefiles instead of ${}. * Puts all build artifacts under build/ (except for the tests, because for now we can't control how runtests invokes the idris binary). * Changes the filename of intermediate outputs to include the CG's name as file extension. This is needed for having better control in the makefile to implement automated bootstrap shortcuts. Discussion available at: idris-lang#1990
201356a
to
e7a1f9c
Compare
Please find the detailed description of this refactor in the form of an upcoming commit extending the documentation with a chapter on the build system. * Eliminates everything bootstrap related beyond the two Makefiles. * Adds a 'make release' target. * Eliminates several sub makefiles from subdirs. * Uses the $() convention in makefiles instead of ${}. * Puts all build artifacts under build/ (except for the tests, because for now we can't control how runtests invokes the idris binary). * Changes the filename of intermediate outputs to include the CG's name as file extension. This is needed for having better control in the makefile to implement automated bootstrap shortcuts. Discussion available at: idris-lang#1990
e7a1f9c
to
4bb1222
Compare
i've rebased the commits to now it's back to the single, mysterious any chance of merging this with that one windows failure? maybe someone who is actively developing on windows can pick this up and debug it that way? |
a reminder: i can see seemingly the same test failures on linux, in the Guix build sandbox: part of the output of the tests is simply missing, and thus many tests fail. last time i checked it was in a consistent manner, but not just one but several dozens. the sandbox is very barren and isolated, it may even miss the glibc UTF-8 locales, etc. |
@attila-lendvai Should at least fix the It looks like you choose what the first step is, build it, then recurse to build the next step. Since nothing changed it repeats. Better to have
This makes I believe recursing the top Makefile is best avoided. Giving the commands to build the scheme files their own target should simplify matters. I don't recall chez020 being an issue in my branch. I've noticed output buffering in a vm, so it could be related to asynchronous vs synchronous (needs to flush)? But in this case it's a pipe? |
There is still a lot that could/should be improved:
TL;DR Not "finished" yet. More thoughts: Another reason to redo the bootstrap: that commit's history is not readily available. Should IDRIS_VERSION be exported? Or just unset it for stage0. If you name it One-stage.mk it would sort nicely :) What's Naming private variables with leading underscore hides it from autocomplete, which is nice. Makes it clear what is public and The build doesn't work if What else can be simplified? @gallais Another concern is this will require commitment to fixes/compatibility, and perhaps time to stabilise, before any new releases. Not sure what plans are there... Might be better to add a --no-compile option now, wait for next version, then tidy up this PR? If this PR is merged as is, half of it would need changed for #1992. |
@benhormann thank you for the detailed feedback! i'll look into implementing them and report back with the result. (and sorry for losing track of those that you have already mentioned previously!) |
@attila-lendvai All good. I could try a PR to your branch, but... I'm working on an alternate implementation / PoC. IMO the stage0 recipe is not really worth including, building prerequisites is normally the caller's responsibility. Question: Is a two stage build useful outside of bootstrapping? If it always builds two stages, is there much difference if it starts from Scheme or installed Idris (assuming first stage from Scheme is cached)? Perhaps... if the installed Idris is significantly newer, such that only one stage is needed. We could have Or we could keep it simple — let the caller decide to self-host or not... Food for thought. (Has the rationale behind the stages been discussed elsewhere?) |
it's more than just an optimization: it enables testing easily whether the version that was marked as the previous evolutionary stage (estage from now on) of the language can bootstrap the current HEAD (as opposed to the currently recorded bootstrap shortcut, i.e. the scheme files checked into the repo). i think anyone who is changing stuff that influences the bootstrap should always run with if the proper bootstrap fails, then it's a sign that a feature of idris has been used in HEAD that is not yet available in the previous estage. such a situation must be resolved either by introducing a new estage, or by rewriting the code without using/assuming anything that has been introduced since the previous estage. idris currently seems to stick to this setup: HEAD must be compilable verbatim both by the previous estage and HEAD itself. in maru (the tiny lisp where i experimented with these things) it's a bit more flexible: there are two variables that the codebase can dispatch on: i'm not sure how applicable this is to idris, though. maru is a tiny, dynamically typed lisp, and it's optimized mostly for sourcecode size + readability/clarity, while avoiding any external dependencies.
i'm not sure i understand your question in this wording. bootstrapping is an essential part of developing idris (and testing/preserving bootstrappability). also, which two stages do you mean? there are 4 stages currently. do you mean simply compiling the scheme files vs. also using it to then compile HEAD?
stage1 being outdated is not a problem as long as its outdatedness is not affecting whether it can compile stage2 (i.e. HEAD). if someone wants to check whether the build is reproducible (i.e. compare the build artifacts in stage2 to stage3), then stage1 must be recent enough so that its compiler's output is the same as that of HEAD.
yes, there's a difference: one tests whether HEAD (or more precisely the current scheme files) can bootstrap HEAD, while the other tests whether the previous estage of the language can bootstrap HEAD. also note re "installed Idris": with this PR i'm also proposing the separation of public releases from the estages of the language that can bootstrap each other in a row. in the current setup they are the same, but it means that whenever a bootstrap stage is necessary for the introduction of a new feature, then a new release of idris also needs to be made. have you read the documentation that i added in this PR? i'm asking because if you have, then it's apparently not written clearly enough. i was hoping that this all is explained there. i'd welcome some feedback on which parts i should extend. (also note that i'm not sure i fully understood all the ideas that you proposed above. if i may sound confused somewhere...) |
I have release version installed at It would be ideal to keep the build artifacts separate, e.g. building 'stage1' compiler having build dirs for 'bootstrap' and 'stage0' compilers. The TTC version can differ at that point (as you are aware). Basically you want to be able to test both and have each only compile modules that changed since last time. Ideally you could run such a test twice and no modules need rebuilt the second time.
Sorry, "bootstrapping" in this project is overloaded. I meant building from Scheme or previous version. I'd say "bootstrapping from GHC" for the traditional meaning. (I mean stage1 and stage2 — stage0 doesn't count i.e. isn't HEAD, and stage3 is not really a build stage). BTW, if the stage3 idris2.ss is identical to stage2 idris2.ss, isn't that enough. What's the point of building the libs too?
The
My understanding is this is intentional. Make evolutionary changes more often than public releases is a hassle (speculation)?
I read it. This description talks about traditional bootstrapping. That's important, but I'm more interested in getting the thing working. It makes more sense to me that we should optimise the Makefile for "build & install" and "testing my changes" scenarios. |
short of much encouragement, i have apparently lost interest in this PR.
it's always just bootstrapping from the previous evolutionary stage of the language. sometimes it just happens to be GHC/Idris1, some other times it's V8.5. i see value in reifying it into the main workflow to keep it in a functional state. i also see value in keeping the language bootstrappable at all times (see the link for the argument), but i don't have enough stake in Idris to advocate for these values more than what i have already done. |
Sorry that you didn't get much feedback but:
As highlighted in the CONTRIBUTING:
|
@gallais no hard feelings, i'm just stating the fact for any other interested parties that i probably won't work on this anymore. i enjoy exploring bootstrapping issues, i had my fun with Idris, but i got exhausted and by now most of it is gone from my short-term memory. whether the result is of any value is up to the maintainers to decide.
i don't think this is a fair statement. the CI was clear for a long time except a single test failure on windows, and i'm pretty sure it's not related to this PR, it only exposes it. even though i hate touching windows, i looked into it, and the value seems to be fine, yet it fails to get printed for some misterious reason. |
My bad, I hadn't looked into the details of the failure. |
what
The main point of this refactor is to:
The detailed description of this PR is in the form of extending the documentation, please see the relevant commit.
some highlights
make release
make check-reproducibility
make prepare-bootstrap-files
build/
checked into git)build/
build/
, i.e. it better exercises the real-life setupnotes
idris.1
..idris.7
branches in my github fork (they don't need to be merged/pushed for this PR to work).status
short of much encouragement from the maintainers, i have apparently lost interest in this PR.
it's ready for review/merge. i only know about one last issues/TODO:
chez/chez020
test fails to printIdris2
, even though the output ofidris2 --version
seems to be fine, and the value, too. and yet, theIdris2
string doesn't reach stdout. this is most probably just exposed by this PR, not caused by it. possibly related to Let bound expressions are evaluated after failed guard in comprehension #2215 or at least the comments over their contain other examples of the same behavior in the Guix build sandbox)install-api
andinstall-with-src-api
(IDRIS2_PREFIX
is used both as the dir to look for libs, and the destination dir of installation (what is usually calledDESTDIR
in GNU parlance). work it around using a kludge in the makefile)IdrisPaths.idr
doesn't get incorporated into the final executable, and thusmake PREFIX=/new/prefix install
installs an executable with the wrongyprefix
value (a reproducer: failure to recompile modules, seemingly randomly #2033). but the best way to resolve it would be to stop capturing the install path into the executable. works when rebased on top of [fix #2033] determining when to rebuild modules #2188for later
downsides
git
executable. but it can do everything withoutgit
that the old makefile used to be able to do.cross refs