automatically generating socket based Tcl / C connection code, 2, using bwise

By Theo Verelst

The previous page on this subject, containing the code fragments, both C and tcl on-page, is automatically generating socket based Tcl / C connection code, 1.

Here I'll look at putting the main parts of the example in BWise blocks and graphs, to make the whole undertaking more insightfull and automated at block level.

Image TV Wiki stubcompile1.jpg

Block functions and value (after 'Funprop'-ing all input blocks into a successfull compile):

 set Proc1.bfunc {exec gcc -c ${} ; set Proc1.out [file rootname ${}].o}
 set Proc1.bfunc_init {}
 set {test.c}
 set Proc1.out {test.o}
 set Proc2.bfunc {exec gcc -c ${} ; set Proc2.out [file rootname ${}].o}
 set Proc2.bfunc_init {}
 set {}
 set Proc2.out {}
 set Proc3.bfunc {exec gcc -c ${} ; set Proc3.out [file rootname ${}].o}
 set Proc3.bfunc_init {}
 set {}
 set Proc3.out {}
 set Proc4.bfunc {exec gcc -o stub ${Proc4.in1} ${Proc4.in2} ${Proc4.in3}  ; set {Proc4.out} stub}
 set Proc4.bfunc_init {}
 set Proc4.in1 {}
 set Proc4.in2 {}
 set Proc4.in3 {}
 set Proc4.out {}

It's not hard to put the above together by hand in bwise, the one in-one out blocks can be made easily in place on the canvas by the right-mouse popup entry 'proc', the three input by:

   newproc {} {} {in1 in2 in3}

the wires by making two pins green and pressing wire. The latest bwise (one file download) currently is here [L1 ].

The idea is that the activating the blocks makes the compile work, which can also be done on the command line, in this case relatively easily by ggc -c the three C source files, and when they are finished, the link phase: gcc -o stub *.o .

As a side remark: on linux (I tried on redhat 9) before starting X and before compiling, try

   export TMP=/dev/shm
   export TEMP=/dev/shm

This seems to make the compiler and some other things (like wmaker) use temporary files on ramdisk (with the risk of losing them over rebooting), which makes compilation much faster, in serious sub-second range.

Currently, bwise has flood and funprop (function argument satisfying block propagation) facilities built in, but no 'draw from all inputs' equivalent, so either a three input block can be feeding all compile blocks to bring the inputs together (passing the various C file names), or we have to by hand funprop all three C compile blocks.

Image TV Wiki stubcompile2.jpg

after adding: eval pro_args newproc {{out {out1 out2 out3}} {in {}}}, and connecting

After adding the above,and setting the blockfunction to empty and the outputs to the particular C files:

   set Proc5.bfunc {}
   set Proc5.out1 serv2.c
   set Proc5.out2 stub.c
   set Proc5.out3 test.c

and on cygwin making sure we have the compiler path included:

   append env(PATH) ";c:\\cygwin\\bin"

we can fire the 'make' equivalent network by using the inputless left block to trigger Funprop.

Now let us see if we can do the calling of our new C compiled program also from Bwise, and see its output. I added a fflush command after the printf's in the stub.c main C code in the previous page, to make sure tcl under cygwin can also read its stdout.

Assuming the blocks above have fired successfully, you should have a stub program in the current directory. Doing the same as on the previous page to run our program and see the result, but now using tcl (I tried all in the same bwise application with console):

 # create a small monitor block
 # start the program we made and monitor stdout
 set fstub [open "|./stub" r+]
 # put the stdout from stub in the mon window
 fileevent $fstub readable {
    if [eof $fstub] {close $fstub} ;
    set r [gets $fstub];
    # puts " $r\n";
    # mon number must match the mon block name you use
    $mc.mon1 insert end $r
 # now connect over the socket

Now press the buttons (shown on previous page) and we have an interactive BWise canvas with C program making and output feedback to a block.

Even more daring it would (and will) be to do the whole compile and resulting program startup on the bwise canvas. And while we're at it, why not start the program up, make its standard output visible, connect with it over its socket, and prepare its termination.

Assuming the following graph hs been made by relatively easy bwise menus and a few commands (for the multiple input/output pins):

Image TV Wiki stubcompile3.jpg

These block functions set up the rest of the chain as just outlined:

 set Proc6.bfunc {set Proc6.out1 [open "|./${}" r+] ; set Proc6.out2 [pid ${Proc6.out1}] }
 set Proc7.bfunc {fileevent ${} readable {if [eof ${}] {close ${} ; return } ; set {Proc7.out} [gets ${}]; $mc.mon2 insert end ${Proc7.out}; $mc.mon2 see end}}
 set Proc8.bfunc { set Proc8.out [exec kill ${Proc8.i1} ]}
 set Proc9.bfunc { set Proc9.out ${} }
 set Proc10.bfunc {socconnect}

So when this graph is started at the left with Funprop, first the program stub gets compiled, then started, its stdout fileevented into the mon window, its PID stored for ;after kill (starting Proc9 with Funprop) and the connection from the previous page set up.

After this, we can start the whole sequence up, possibly after editing test.c, and immediately test the program with the buttons window!

When someone wants to play around with this, or nick some tricks, I put some working sources in this zip file:


the can* files are bwise canvas files, in this case of a later version which saves the block variables (functions and 'state' of the canvas) as well.

One C file is (was) in fact generated by the example on the previous page. It actually works, not tricks, try for yourself.

The Mon2 block you'll have to recreate yourself, it's an unfortunately currently still unresolved work area to make the bwise blocks save themselves also when containing widgets. I'm sure it's possible. Make sure you are in the dir with the C source files, and if you want to press buttons, the previous page makes the code for them.

   source canstub2.tcl

Double click Mon2, press 'Del Sel'(ection) and use

   newmon {} Mon2

make a wire where it was before.

   source proccstub.tcl
   set socfs {message1 message2 message3 {another message} message7}

I was just trying the stuff from the zip file on a safe linux account (read: hardly any permissions), which works nicely, but of course requires still *way* too much knowledge and assumes a lot of things non-explicitly.

First starting programs, making connections with a working socket address, give it time to connect, handle errors, stop programs, especially after errors. Lots of stuff.

I just found out my redhat has the well known defunct process problem, requiring me to start bwise to get a killed child process to actually be killed, and stop occupying a fixed socket number. Grr. That has to change.

Also, on windows I got no error with the current code when killing the 'stub' program, but on linux it generates an error with the 'close' from the proc7 event command (I think).