[ECOS] The John's Ousterhout Tcl 6.7 under eCos

Sergei Gavrikov w3sg@SoftHome.net
Thu Jun 29 16:04:00 GMT 2006


You will have the old, good, full featured Tcl 6.7 from John Ousterhout
under eCos. There will be one limitation for this port. You won't get
support for the pipelines and Tcl exec command. But, if you want to get
a shell, or get a glue, or have an instrument, that Tcl does it all.

That's it!

 	Sergei Gavrikov
-------------- next part --------------
How to get the John's Ousterhout Tcl 6.7 under eCos


	What you will get?
	How much memory does it use?
	Is the Tcl 6.7 slow?
	Let's build Tcl for eCos!
	puts "Wish you were here!"

What you will get?

You will have the old, good, full featured Tcl 6.7 from John Ousterhout under
eCos. But, there will be one limitation for this port. You won't get support
for the pipelines and Tcl exec command. The exec command will not work.  If you
know, eCos is not an Unix. I didn't remove any unix parts from the Tcl sources.
I thought it is better to get an error on unsupported command (and catch it)
then mess with code. Below are two examples illustrating that:

% set f [open {|ls /bin} r]
Error: couldn't create output pipe: Not supported
% exec /bin/ls
Error: couldn't create output pipe: Not supported
% _

But don't worry, you will be able to open regular files with Tcl!

% set f [open /var/tmp/file w]
% puts $f "I like this Tcl!"
% close $f
% set f [open /var/tmp/file r]
% while {[gets $f line]>=0} {puts $line}
I like this Tcl!
% close $f
% _

How much memory does it use?

The full featured Tcl library size is only 95k. You will find everything in
that library: floating-point support in `expr', `regexp', `regsub', `puts',
`file', etc.  I.e. there are Tcl 6.7 generic and unix command sets in the

When I build Tcl 6.7 shell with `-DTCL_ENERIC_ONLY' option, I got:

$ arm-elf-size tclsh6.7-generic
   text    data     bss     dec     hex filename
 150292    2620   19548  172460   2a1ac tclsh6.7-generic

When I build it without that option, I got:

$ arm-elf-size tclsh6.7-unix
   text    data     bss     dec     hex filename
 184592    2860   19696  207148   3292c tclsh6.7-unix

When I build it with `-DTCL_MEM_DEBUG' option, I got:

$ arm-elf-size tclsh6.7-memdbg
   text    data     bss     dec     hex filename
 190892    2908   19684  213484   341ec tclsh6.7-memdbg

I like these results. Note: all builds were with the `-Os' gcc optimization

Is the Tcl 6.7 slow?

Yes, it is. The Tcl's battle-cry was: all is a string. It is an unix ideology
and I like it.  If you want to get a shell, or get a glue, or have an
instrument, the Tcl does it all. But it doesn't promise to be a RT (real-time)
Tcl. Let's look on the Tcl under eCos as main (or single) eCos thread which
acts together with yours RT procedures (or threads) in C. If eCos Tcl's speed
is your main concern, there is another small footprint implementation of Tcl -
Jim (http://jim.berlios.de.) Below is the results of speed comparison between
Jim and Tcl6.7 on my 15 VAX mips board:

% time {for {set i 0} {$i < 1000} {incr i} {set x 0; unset x}} 10 ;# Jim
431000 microseconds per iteration
% _

% time {for {set i 0} {$i < 1000} {incr i} {set x 0; unset x}} 10 ;# Tcl6.7
1078000 microseconds per iteration
% _

Let's build Tcl for eCos!

The first step is to configure eCos tree. Configuration has to include at
least: eCos `default' template, +posix, +fileio ?+romfs? ?+ramfs?. Build the
eCos (you can do it as well).

Download, uncompress, untar the tcl6.7 tar-ball from the Tcl ftp archive
(ftp://ftp.tcl.tk): /pub/tcl/tcl_old/tcl6.7.tar.Z.

Do some changes to the `tcl6.7/config' file. The minimum recommendations are

set includeDir="${ecosInstallDir}/include"
set libcFiles="${ecosInstallDir}/lib/libtarget.a"

set CC="${ecosCommandPrefix}gcc"
set AR="${ecosCommandPrefix}ar"
set RANLIB="${ecosCommandPrefix}ranlib"
set NM="${ecosCommandPrefix}nm"

In the config file replace all references on the gnu binutils (nm, ar, ranlib)
and cc by the following variables.

Build Tcl dependences (csh script will update tclUnix.h, and Makefile).

	ecosInstallDir=<ECOS_INSTALL_DIR> \
	ecosCommandPrefix=<ECOS_COMMAND_PREFIX> \


	ecosInstallDir=~/ecostcl/install ecosCommandPrefix=arm-elf- ./config

Note: `config' is a csh script. It needs to be in the csh.

Fix the Tcl 6.7 Makefile: see the eCos `examples/Makefile' for a sample.

I recommend enter -D_ECOS into a CFLAGS (or TCL_CFLAGS) definition of the

Try to build the libtcl.a, be a hacker!

You will get a lot of "noise" when you type `make'! I've got it. Fix a few
wrong(s) and missing(s). I touched the tclUnix.h and tclUnixStr.c only. I enter
only 3 #ifdef __ECOS__ wrappers  there. Is there patch in this document? No, it
isn't.  Why? I think you can use other GCC compiler, and certainly other target
board, so, here is some hints in the document.

$0.02: the '-Wno-strict-prototypes' is useful gcc switch for the old C sources.

I found what SIGINT, ECHILD constants have been missed in the eCos headers.
Let's put such definitions in the tclUnix.h file. There is no <sys/file.h>, but
there is a suitable <cyg/io/file.h> file in the eCos include path. Fix it in
the tclUnix.h header.

Place following 3 entry in the suitable places in the tclUnix.h:

#ifndef __ECOS__
#   if defined(_ECOS) || defined(ECOS)
#      define __ECOS__
#   endif

#ifndef __ECOS__
#   include <sys/file.h>
#   include <cyg/io/file.h>

#ifdef __ECOS__
#   define ECHILD 10
#   define SIGINT 2

There was yet another surprise in one header. There is EDEADLK value same as
EDEADLOCK in the <cyg/error/codes.h>.

cyg/error/codes.h:#define EDEADLK          35
cyg/error/codes.h:#define EDEADLOCK        EDEADLK

It will occur as an error for tclUnixStr.c. So, you will have to fix it as:

#if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLK != EDEADLOCK))
	case EDEADLOCK: return "EDEADLOCK";

Now, let's filter all libc symbols that contains in libtarget.a file. We know
that most of the libc (unix) functions were named laconic (its name length is
less than 14 ascii symbols).

${NM} -p libtarget.a | grep -E '\WT\W[^_]{1,14}$' | sort >libc.tmp

There were no `endpwent', `execvp', `fork', `getpwnam', `isascii', `kill',
`lstat', `mktemp', `pipe', `readlink' and `wait' entries in my libc.tmp. It is
my case!. I needed them. So, I did a dirty fix to build libtcl.a successfully.

cat >compat.c<<__eof
#include <errno.h>
lstat(f,b){return stat(f,b);}
readlink(p,b,s){int n,f;if(f=open(p,1)==-1)return(-1);n=read(f,b,s);close(f);return(n);}

I hope, you will be able to make your own compat.c file (more nicer then me) to
fix any eCos missings.  Here's to your success!

In that time, I set the COMPAT_OBJS variable (tcl6.7/Makefile) to

COMPAT_OBJS = compat.o

Yep! It is my addendum for the tclTest.c to support rom/ram file system:

#ifdef __ECOS__
#include <pkgconf/system.h>

#if !defined(CYGPKG_IO_FILEIO)
#  error CYGPKG_IO_FILEIO missing

#if !defined(CYGPKG_FS_RAM)
#  error CYGPKG_FS_RAM missing

#if !defined(CYGPKG_FS_ROM)
#  error CYGPKG_FS_ROM missing

#include <pkgconf/io_fileio.h>
#include <cyg/fileio/fileio.h>

/* Fix it!  */
#ifndef FS_ROM_ENTRY
#  define FS_ROM_ENTRY 0x80020000
#  warning ROMFS entry will been mounted at 0x80020000

MTAB_ENTRY( romfs_mte1,

/* put maketempfs() call in main() (before Tcl_CreateInterp) */
#define maketempfs()                        \
    do {                                    \
            mount ("", "/var", "ramfs");    \
            mkdir ("/var/tmp", 0777);       \
    } while (0);

I am sure, you will be able to link a `tclTest' program (look on it as a
tclsh). Even if you will use the -DTCL_GENERIC_ONLY in the CFLAGS, you will
have an `echo' command instead a unix Tcl `puts' command. There is the `echo'
command in the tclTest.c. 

Well, a generic Tcl has been built. Rename it to tclsh6.7-generic. Now, try
rebuild all without that flag. You will have to build tclsh6.7-unix. 

If it does, I would strongly recommend you to build one more image:
tclsh6.7-memdbg.  Rebuild everything with the `-DTCL_MEM_DEBUG' option and save
tclTest as tclsh6.7-memdbg.

puts "Wish you were here!"

Let's play with the Tcl!

I pass well known RedBoot commands about the loading of our images. Hope, you
will be able to do same list:

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0x80000000  0x81008000  0x00020000  0x81008040
[rom fs]          0x80020000  0x81007000  0x00010000  0x81007000
tclsh6.7-generic  0x80030000  0x81008000  0x00030000  0x81008040
tclsh6.7-memdbg   0x80060000  0x81008000  0x00030000  0x81008040
tclsh6.7-unix     0x80090000  0x81008000  0x00030000  0x81008040
FIS directory     0x803F0000  0x803F0000  0x0000F000  0x00000000
RedBoot config    0x803FF000  0x803FF000  0x00001000  0x00000000

RedBoot> fis load tclsh6.7-memdbg
RedBoot> go
% lsort [info commands]
append array auto_execok auto_load auto_mkindex auto_reset break case catch cd
checkmem close concat continue echo eof error eval exec exit expr file flush
for foreach format gets glob global history if incr info join lappend lindex
linsert list llength lrange lreplace lsearch lsort memory open proc puts pwd
read regexp regsub rename return scan seek set source split string tell time
trace unknown unset uplevel upvar while

Let's test the /usr/local/lib/tcl/init.tcl. I used the romfs image as read-only
root unix entry: /. In my case the romfs image is placed in one 64k-block of
the FIS. Pleasure to have any filesystem on an embedded system, so, usually I
mount a ramfs  on /var too. It is R/W filesystem to test the Tcl's file i/o.

% cd
Error: couldn't find HOME environment variable to expand "~"
% set env(HOME) / ;# let's do it
% cd
% hostname
Error: can't read "env(PATH)": no such element in array
% set env(PATH) /bin ;# well, it's faked yet
% hostname
Error: invalid command name "hostname"
% _

That's all right, we see that Tcl's `auto_load' works.

There is the parray.tcl in the TCL_LIBRARY directory.

% glob [info library]/*
/usr/local/lib/tcl/init.tcl /usr/local/lib/tcl/tclIndex /usr/local/lib/tcl/parray.tcl
% _

% parray env
env(HOME) = /
env(PATH) = /bin
% _

And what is that `memory' command? I didn't use it... What's its syntax?  Try
to learn the command as usual.

% memory blah
Error: bad option "blah":  should be info, init, active, break_on_malloc,
trace_on_at_malloc, trace, or validate

% memory info
total mallocs                    194
total frees                       15
current packets allocated        179
current bytes allocated         8161
maximum packets allocated        179
maximum bytes allocated        15042

% memory trace on
% set v 0
ckalloc 8103f0ac 18 tclHash.c 519
ckalloc 8103f0ec 28 tclVar.c 2061
% unset v
ckfree 8103f0ac 18 tclHash.c 157
ckfree 8103f0ec 28 tclVar.c 685

I get you!

At last make the Tcl panic to learn more about its allocators:

% while {1} {append t {loooooooooooooooong liiiiiiiiiiiine}}
total mallocs                    210
total frees                       29
current packets allocated        181
current bytes allocated       311328
maximum packets allocated        182
maximum bytes allocated       462904
unable to alloc 606232 bytes, tclVar.c line 2061

Comment: I have a 1M of RAM on my board. There are the 32k-chunk (for RedBoot),
64k-chunk (for ramfs) and 214k-chunk (for tclsh) in the RAM. Total used size is
~312k.  The last successful allocation was ~463k, and next fail attempt was to
allocate a 606k. Big deal! Tcl ran out of memory...

That's it!

	Sergei Gavrikov

-------------- next part --------------
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

More information about the Ecos-discuss mailing list