larsbrinkhoff / lbForth

Self-hosting metacompiled Forth, bootstrapping from a few lines of C; targets Linux, Windows, ARM, RISC-V, 68000, PDP-11, asm.js.
GNU General Public License v3.0
414 stars 113 forks source link

Fedora Core 25 x86 64 bits target #60

Closed frno7 closed 6 years ago

frno7 commented 7 years ago

I thought it would be interesting to try out lbForth. Target is Fedora Core 25 x86 64 bits and here are my notes:

make -ftargets/c/bootstrap.mk
make[1]: Entering directory '/usr/local/src/lbForth'
make[1]: Circular kernel.c <- b-forth dependency dropped.
gcc -m32 -O2 -fomit-frame-pointer -fno-unit-at-a-time -Itargets/c targets/c/params.c -o params
In file included from /usr/include/features.h:392:0,
                 from /usr/include/string.h:25,
                 from targets/c/params.c:1:
/usr/include/gnu/stubs.h:7:27: fatal error: gnu/stubs-32.h: No such file or directory
 # include <gnu/stubs-32.h>
                           ^
compilation terminated.
targets/c/forth.mk:25: recipe for target 'params' failed
make[1]: *** [params] Error 1
make[1]: Leaving directory '/usr/local/src/lbForth'
Makefile:27: recipe for target 'b-forth' failed
make: *** [b-forth] Error 2
larsbrinkhoff commented 7 years ago

gnu/stubs-32.h is missing (it‘s not installed by default on 64 bits FC25), but it seems to work by simply removing -m32 in targets/c/forth.mk (see compiler log below).

By default, the bootstrap Forth is built with the 32-bit GCC toolchain. For that, you will have to install build dependencies such as 32-bit libraries and header files. I don't know how to do that for Fedora.

But removing -m32 to get a 64-bit build works equally well.

Make warns about “circular kernel.c <- b-forth dependency dropped” (see compiler log below).

Yes. I have looked into it, and concluded it was harmless. I recall it was only during the bootstrap.

lbForth prints “File not found” but it would be helpful if the failed file path is printed too.

You're right. I'll make a separate issue for that.

I used s" /some/dir/..." searched to make lbForth find source files of interest. Not sure if this is correct but it did seem to work.

Yes, that's the intention.

The search path seems to be limited to 23 characters which caused some problems with mangled file paths.

This is probably issue #55. Can you build a native Forth, e.g. make TARGET=x86 OS=linux? If so, the new Forth should not have this issue.

require subdirectories seems to be lost, so that foo in require foo/bar.fth is ignored?

No, they are not supposed to be lost. Can you provide a specific example?

The code I tried makes use of Forth locals to some extent, and it seems src/locals.fth doesn’t implement it

No, it doesn't. I never felt any need to use locals, to that file is just a stub.

frno7 commented 7 years ago

Yes, issue #55 is the same thing. I tried the subdirectories again, and it seems to work (I might have confused it with the 23 character truncation). It seems parallel build causes problems:

lbForth % make clean && make -j8
rm -f *.o kernel.c params* params.fth jump.fth threading.fth target.fth
rm -f forth *-forth test-* *-stamp *.exe conf.mk forth.html forth.js
make -ftargets/c/bootstrap.mk
gcc  -O2 -fomit-frame-pointer -fno-unit-at-a-time -Itargets/c targets/c/params.c -o params
rm -f *-stamp
make[1]: Entering directory '/usr/local/src/lbForth'
make[1]: Circular kernel.c <- b-forth dependency dropped.
gcc  -O2 -fomit-frame-pointer -fno-unit-at-a-time -Itargets/c targets/c/params.c -o params
cp targets/c/jump.fth jump.fth
cp targets/ctc.fth threading.fth
cp targets/c/target.fth target.fth
touch c-.-stamp
echo ": sysdir   s\" src/\" ;" >> target.fth
cp targets/c/jump.fth jump.fth
cp targets/ctc.fth threading.fth
cp targets/c/target.fth target.fth
echo ": sysdir   s\" src/\" ;" >> target.fth
targets/c/run.sh ./params -forth > params.fth
targets/c/run.sh: line 11: ./params: Text file busy
targets/c/forth.mk:22: recipe for target 'params.fth' failed
make: *** [params.fth] Error 126
make: *** Waiting for unfinished jobs....
targets/c/run.sh ./params -lisp > params.lisp
./lisp/lisp.sh '(load "lisp/meta.lisp") (compile-forth "targets/c/nucleus.fth" "src/kernel.fth")'
gcc  -O2 -fomit-frame-pointer -fno-unit-at-a-time -Itargets/c  -c -o kernel.o kernel.c
gcc  kernel.o -o b-forth
rm -f kernel.c kernel.o params.lisp jump.fth threading.fth target.fth
make[1]: Leaving directory '/usr/local/src/lbForth'

I tried make TARGET=x86 OS=linux but it seems to continue when it fails:

lbForth % make TARGET=x86 OS=linux
rm -f *-stamp
touch x86-linux-stamp
cat targets/x86/params.fth targets/x86/linux/params.fth > params.fth
cp targets/x86/jump.fth jump.fth
cp targets/itc.fth threading.fth
cat targets/x86/target.fth targets/x86/linux/target.fth > target.fth
echo ": sysdir   s\" /usr/local/share/lbForth/\" ;" >> target.fth
echo include targets/x86/meta.fth | targets/c/run.sh ./forth | tail -n+3 > x86-forth
mv image x86-forth
mv: cannot stat 'image': No such file or directory
targets/x86/forth.mk:5: recipe for target 'x86-forth' failed
make: [x86-forth] Error 1 (ignored)
chmod a+x x86-forth
rm -f forth.exe
cp x86-forth forth

It then claims nothing is to be done:

lbForth % make TARGET=x86 OS=linux
make: Nothing to be done for 'all'.

It’s easy to get tripped-up in some unbuildable state. Trying just make (that did work before) after this gives:

lbForth % make
rm -f *-stamp
touch c-.-stamp
targets/c/run.sh ./params -forth > params.fth
cp targets/c/jump.fth jump.fth
cp targets/ctc.fth threading.fth
cp targets/c/target.fth target.fth
echo ": sysdir   s\" src/\" ;" >> target.fth
echo 'include targets/c/meta.fth  bye' | targets/c/run.sh ./forth | tail -n+3 > kernel.c ; grep -a Meta-OK kernel.c
targets/c/run.sh: line 11:  9881 Segmentation fault      (core dumped) PATH="$TPATH" "$@"
targets/c/forth.mk:19: recipe for target 'kernel.c' failed
make: *** [kernel.c] Error 1

Trying make clean, make and make TARGET=x86 OS=linux and yet another make gives:

lbForth % make
gcc  -O2 -fomit-frame-pointer -fno-unit-at-a-time -Itargets/c  -c -o kernel.o kernel.c
gcc  kernel.o -o c-forth
kernel.o: In function `exit_code':
kernel.c:(.text+0x3): undefined reference to `RP_word'
kernel.c:(.text+0x11): undefined reference to `RP_word'
kernel.o: In function `dodoes_code':
kernel.c:(.text+0x23): undefined reference to `SP_word'
kernel.c:(.text+0x2e): undefined reference to `SP_word'
kernel.c:(.text+0x3d): undefined reference to `RP_word'
kernel.c:(.text+0x48): undefined reference to `RP_word'
kernel.o: In function `zerobranch_code':
kernel.c:(.text+0x63): undefined reference to `SP_word'
kernel.c:(.text+0x79): undefined reference to `SP_word'
kernel.o: In function `_literal__code':
kernel.c:(.text+0x93): undefined reference to `SP_word'
kernel.c:(.text+0x9e): undefined reference to `SP_word'
kernel.o: In function `store_code':
kernel.c:(.text+0xb3): undefined reference to `SP_word'
kernel.o:kernel.c:(.text+0xc8): more undefined references to `SP_word' follow
kernel.o: In function `greaterr_code':
kernel.c:(.text+0x13b): undefined reference to `RP_word'
kernel.c:(.text+0x146): undefined reference to `RP_word'
kernel.o: In function `rto_code':
kernel.c:(.text+0x153): undefined reference to `RP_word'
kernel.c:(.text+0x161): undefined reference to `RP_word'
kernel.c:(.text+0x16b): undefined reference to `SP_word'
kernel.c:(.text+0x176): undefined reference to `SP_word'
kernel.o: In function `nand_code':
kernel.c:(.text+0x183): undefined reference to `SP_word'
kernel.c:(.text+0x198): undefined reference to `SP_word'
kernel.o: In function `cstore_code':
kernel.c:(.text+0x1b3): undefined reference to `SP_word'
kernel.o:kernel.c:(.text+0x1c8): more undefined references to `SP_word' follow
kernel.o: In function `main':
kernel.c:(.text.startup+0x5): undefined reference to `turnkey_word'
kernel.c:(.text.startup+0xc): undefined reference to `sp0_word'
kernel.c:(.text.startup+0x17): undefined reference to `rp0_word'
kernel.c:(.text.startup+0x22): undefined reference to `dp0_word'
kernel.c:(.text.startup+0x2f): undefined reference to `limit_word'
kernel.c:(.text.startup+0x3a): undefined reference to `latest0_word'
kernel.c:(.text.startup+0x3e): undefined reference to `turnkey_word'
kernel.c:(.text.startup+0x45): undefined reference to `SP_word'
kernel.c:(.text.startup+0x50): undefined reference to `RP_word'
collect2: error: ld returned 1 exit status
targets/c/forth.mk:14: recipe for target 'c-forth' failed
make: *** [c-forth] Error 1
frno7 commented 7 years ago

Small functions like gcd and lcm are perhaps somewhat manageable without locals:

: gcd ( n1 n2 -- n3 ) begin ?dup while tuck mod repeat abs ;
: lcm ( n1 n2 -- n3 ) 2dup * abs -rot gcd / ;

But the extended Euclidean algorithm is another matter where 7 numbers are involved in various ways. One of them is tacit here:

: extended-gcd ( n1 n2 -- n3 n4 n5 )
    1 0 0 1 { n m d c b a }
    begin   m 0<>
    while   n s>d m sm/rem nip ( Symmetric division is required: n m / )
        dup a * c swap - to c
        dup b * d swap - to d
            m * n swap - to n
        a c to a to c
        b d to b to d
        m n to m to n
    repeat n 0< if d negate c negate n negate else d c n then ;

The gcd for Gaussian integers is yet another step up in complexity. :) I’ve made a Scheme version but haven’t translated it to Forth yet:

(define (extended-gcd w z)
 (letrec ((loop
   (lambda (w z a b c d)
     ; Solve [ a b | w ]
     ;       [ c d | z ].
     (cond ((= w 0) (values z c d))
           ((= z 0) (values w a b))
           ((or (<= (real-part w) 0) (< (imag-part w) 0))
            (loop (* w 0+i) z (* a 0+i) (* b 0+i) c d))
           ((or (<= (real-part z) 0) (< (imag-part z) 0))
            (loop w (* z 0+i) a b (* c 0+i) (* d 0+i)))
           ((<= (magnitude w) (magnitude z))
            (let ((q (floor (/ (magnitude z) (magnitude w)))))
              (loop w (- z (* w q)) a b (- c (* a q)) (- d (* b q)))))
           (else (loop z w c d a b))))))
   (loop w z 1 0 0 1)))

This Euler phi function is almost completely tacit:

: euler-phi ( n1 -- n2 )
    1 { p } factor-exponents 0 ?do
        2dup ** -rot 1- ** - p * to p
    loop p ;

I now came up with this alternative but I’m unsure readability improves:

: euler-phi ( n1 -- n2 )
    factor-exponents 1 swap 0 ?do >r 2dup ** -rot 1- ** - r> * loop ;
larsbrinkhoff commented 7 years ago

I have never tried parallel builds before, but now that I do, I see there is a problem.

larsbrinkhoff commented 7 years ago

There's a quirk with the build system. You should always pass the same values of TARGET and OS every time you run make. If you do that, I think you'll see most problems go away. But stay away from parallel builds. There shouldn't be much to gain anyway.

larsbrinkhoff commented 7 years ago

Regarding locals, I'm not opposed to providing them as a loadable extension, but it's not a priority.

Not having locals is also a way to encourage learning to write Forth without them.

frno7 commented 7 years ago

I’m a bit confused as to whether the “ignored” error (from complete compiler log above) in

...
echo include targets/x86/meta.fth | targets/c/run.sh ./forth | tail -n+3 > x86-forth
mv image x86-forth
mv: cannot stat 'image': No such file or directory
targets/x86/forth.mk:5: recipe for target 'x86-forth' failed
make: [x86-forth] Error 1 (ignored)
chmod a+x x86-forth
rm -f forth.exe
cp x86-forth forth

using make TARGET=x86 OS=linux actually produced a working x86 target binary after all.

larsbrinkhoff commented 7 years ago

Yes, people do understandably get confused by that.

The reason is there are two ways the Forth image can be rebuilt. The bootstrap Forth writes it to stdout, hence the > x86-forth. But the real Forth writes it to a file called image, hence the mv image x86-forth.

In the first case, no file called image is created, so the mv command fails. This is harmless.

You can verify that the binary works by running make check TARGET=x86 OS=linux.

frno7 commented 7 years ago

Thanks, make check TARGET=x86 OS=linux appears to work!

This is probably issue #55. Can you build a native Forth, e.g. make TARGET=x86 OS=linux? If so, the new Forth should not have this issue.

Paths on the x86 target seem to be truncated at 44 characters instead of 23 of the other target:

lbForth % echo 's" /a/long/path/that/appears/be/truncated/" searched require FOO.FTH' |
            strace -e open ./x86-forth 2>&1 | grep appears
open("/a/long/path/that/appears/be/trFOO.FTH", O_RDONLY) = -1 ENOENT (No such file or directory)
larsbrinkhoff commented 7 years ago

Ah, that's right. I forgot there is a limit there too. I added this information to #55.

larsbrinkhoff commented 6 years ago

I think this can be closed. There are sepate issues for each of the problems.