Reading a TCL variable in a Makefile - makefile

I am trying to read (and eventually set to a Make variable) the value of a variable set in a TCL script in order to echo it to a file.
(I know I can simply puts the var to the file, but it's a more complicated flow, and doing it in the Make would be easier. Just want to know if this is possible)
Set final_val "Test finished! No Failures"
I then want to use the value of final_val (set in the TCL) in the Makefile that calls the script:
#file.tcl
#echo final_val >> $(out_file)
P.S. I am on TCL 8.5

It's not trivial to get a value in a Tcl script into a make run. The simplest way might be to arrange for the script to produce that variable as its only output, as you can then use a fairly simple approach:
On the Tcl side:
#!/usr/bin/env tclsh
set final_val "Test finished! No Failures"
puts $final_val
On the Make side (assuming you've made everything executable):
FINAL_VAL := $(shell thescript.tcl)
There's a lot more complexity possible than just this, of course, but this is the simplest technique that could possibly work.
If you're producing a lot of output in that script, you might need to instead use a separate post-processing of the output to get the part you want. That can get really complex; those cases are often better off being converted to using intermediate files, possibly with recursive makes, as you don't really want to have significant processing done during the variable definition phase of processing a makefile (as it causes real headaches when it goes wrong, and puts you in a world of pain with debugging).
One way that's more complex but which works really well for me is to make the Tcl code generate some file, perhaps outputinfo.mk, that contains the make variable definitions that I want. (On the Tcl side, you're just writing to a file. There's loads of ways to do that.)
Then, I'd make the main makefile have a dependency rule that says that you generate outputinfo.mk you need to run the Tcl script, and then say that the makefile wants to include that outputinfo.mk:
outputinfo.mk:
thescript.tcl > outputinfo.mk
include outputinfo.mk
(For the sake of argument, I'm assuming here that the script writes the file contents to stdout with puts.)
This works well, since make knows about such dependencies caused by include and does the right thing.

Related

accelerate Tcl eval

I'm currently writing a Tcl-based tool for symbolic matrix manipulation, but the code is getting slow. I'm looking for ways to accelerate my Tcl code (Tcl version 8.6).
I have one suspicion. My code builds lists with a command name as the first element and command arguments as the following elements (this comes from emulating an object-oriented approach). I use eval to invoke these commands (and this is done often in the recursive processing). I read at https://wiki.tcl-lang.org/page/eval and https://wiki.tcl-lang.org/page/Tcl+Performance that eval may be slow.
I have three questions:
What would be the fastest way to invoke a command from a list with command name and parameters which is constructed just beforehand?
Would it accelerate the code to separate the command name myCmd and the parameter list myPar and invoke the command with [$myCmd {*}$myPar] instead (suggested at https://stackoverflow.com/a/27619692/3852630)?
Is the trick with if 1 instead of eval still promising in 8.6?
Thanks a lot for your help!
Above all, don't assume: time it to be sure. Be aware when timing things that repeatedly running a thing may change the time it takes to run it (as caches warm up). Think carefully about what you want to actually get the speed of.
The eval command is usually slow, but not in all cases. If you give it a list that you've constructed (e.g., with list or linsert or lappend or…) then it's fairly fast as it can avoid reparsing the input; it knows, but only in that case, that it can skip straight to dispatching to the command implementation. The other case that is fast is when you give it a value that was previously given to eval; the bytecode is already built and cached. These notes also apply with uplevel.
Doing $myCmd {*}$myParameters is fairly fast too; that's bytecoded into “assemble the words on the Tcl operand stack and do the right command dispatch” which is very close to what it would be for an arbitrary user command anyway (which very rarely have direct bytecode implementations).
I'd expect things with if 1 to be very quick in some cases and very slow in others; it forces full compilation, so if things can be cached well then that will be fast and if things can't it will be slow. And if you're just calling a command, it won't make much difference at all at best. The cases where it wins are when the thing being called is itself a bytecoded command and where you can cache things correctly.
If you're dealing with an ordinary command (e.g., a procedure, or one of Tcl's commands that touch the OS), I'd go with option 2: $myCmd {*}$myParameters or variants on it. It's about as fast as you're going to get. But I would not do:
set myParameters [linsert $myOriginalValues 0 "literal1" [cmdOutput2] $value3]
$myCmd {*}$myParameters
That's ridiculous. This is clearer and cleaner and faster:
$myCmd "literal1" [cmdOutput2] $value3 {*}$myOriginalValues
Part of the point of expansion syntax ({*}) is that you don't need to do complex argument marshalling, and that's good because complexity is hard to get right all the time.
A note about K and unsharing objects
Avoid copying data in memory. Change
set mylist [linsert $mylist 0 some new content]
to
set mylist [linsert $mylist[set mylist ""] 0 some new content]
This dereferences the value of the variable and then sets the variable to
the empty string. This reduces the variable's reference count.
See also https://stackoverflow.com/a/64117854/7552

Preprocess conditional arch/make file to get non-conditional file

I have a conditional makefile (well, actually I am dealing with the arch file that will be called when invoking make) that is quite involved and I would like to preprocess it to get rid of all the 'ifeq', 'ifneq' parts that only worsen the readability, in order to see better what is being actually done. I tried doing
make -n -d
where I get the whole calls to the compiler, but that is also a pain since then I need to separate manually all the flags. I just want to get my nice makefile with my separate FLAGS, DFLAGS, LIBS sentences etc etc.
(My apologies if this has been said anywhere, but I am unable to find it).
Thanks!

How to deal with a script that outputs multiple files in a Makefile?

So I have a script, myscript.py, that produces a few output files, out/a.pickle, out/b.pickle, and out/c.pickle
And I have a Makefile that has the rule:
out/a.pickle: data/data.csv
myscript.py
Now, If I update the script, firstly, make out/a.pickle says there's nothing to be done here, even though the script has been modified. Isn't make supposed to check to see if things have been updated and then run them? Do I need to add myscript.py as a dependency to out/a.pickle, or something?
Secondly, is there a way to handle the fact that the script has multiple output files? Do I need to create a rule for each?
Make does not examine time stamps on executables. Otherwise, you would have to recompile the universe if gcc or echo or the shell is upgraded, and it's a slippery slope anyway; what if libraries or the kernel also changed in a way which requires you to recompile? You need human intervention at some point anyhow. So the designers of make simply drew the line at explicit dependencies.
(GNU Make has a lot of other built-in implicit dependencies, which are convenient. I vaguely believe that the original make didn't have any built-in dependencies at all. Anybody able to confirm?)
You can declare all the outputs in one rule:
out/a.pickle out/b.pickle out/c.pickle: myscript.py data/data.csv
./$^
(Notice how the script is included in the dependencies now. You might want to change that after the script is considered stable. Then you'll need to change the action as well.)

Shell scan for variables in "C" source program

Can anyone help me with some advice on how to solve the following problems?
The idea of the problem is to scan a Foo.c file to find all variables, how many times they occur, and the lines were they do occur.
The implementation can be in at least one of the methods:
Build a bat script and eventually additional C program(s)
to solve the problem. Run the implementation in a cmd window.
Build a ps1 script and eventually additional C program(s)
to solve the problem. Run the implementation in a PowerShell window.
I think that, in order to get all variable declarations and uses, and only variable declarations and uses, you're going to need to at least partially parse the source files and analyze the resulting abstract syntax trees.
Your first step, then, is to either write a parser or figure out how to utilize an existing one.
If you are programming C# you can use ANTLR V3 to parse your sources the "C" grammar exists.
You could certainly try to write this as a bat script, but believe me, I've written close to 200 bat scripts and it's horrendous. cmd.exe's findstr would be your friend, but between bat and regex, you're gonna go crazy. Powershell would definitely be better, however a real scripting language would be your best bet, like perl, ruby, or python.
Luckily, in your case anyways, all var in C are explicitly declared, so you could scan once for all the var declarations and create an array of them. Then, scan a second time looking for instances of those variable names. Total number of instances would be total_times_seen -1 since the first would be the var declaration. This assumes of course they are only declared once...

Compilers for shell scripts

Do you know if there's any tool for compiling bash scripts?
It doesn't matter if that tool is just a translator (for example, something that converts a bash script to a C program), as long as the translated result can be compiled.
I'm looking for something like shc (it's just an example -- I know that shc doesn't work as a compiler). Are there any other similar tools?
A Google search brings up CCsh, but it will set you back $50 per machine for a license.
The documentation says that CCsh compiles Bourne Shell (not bash ...) scripts to C code and that it understands how to replicate the functionality of 50 odd standard commands avoiding the need to fork them.
But CCsh is not open source, so if it doesn't do what you need (or expect) you won't be able to look at the source code to figure out why.
I don't think you're going to find anything, because you can't really "compile" a shell script. You could write a simple script that converts all lines to calls to system(3), then "compile" that as a C program, but this wouldn't have a major performance boost over anything you're currently using, and might not handle variables correctly. Don't do this.
The problem with "compiling" a shell script is that shell scripts just call external programs.
In theory you could actually get a good performance boost.
Think of all the
if [ x"$MYVAR" == x"TheResult" ]; then echo "TheResult Happened" fi
(note invocation of test, then echo, as well as the interpreting needed to be done.)
which could be replaced by
if ( !strcmp(myvar, "TheResult") ) printf("TheResult Happened");
In C: no process launching, no having to do path searching. Lots of goodness.

Resources