1

I'm trying to run a tcl script from some specific path on my PC from a C++ program. Unfortunately, I do not have any idea how to do so. Please advise how I can execute a tcl script from a C++ program. An example would be appreciated. For now, I have tried using the Tcl_Eval command.

mrcalvin
  • 3,291
  • 12
  • 18
user12755014
  • 25
  • 1
  • 5
  • 1
    Hello, your question is a bit broad and it is hard to know what you have tried? I would help if you could show us some (working) code, with an explanation of how it does not achieve what you want. – BobMorane May 24 '20 at 13:56
  • For example, it would be helpful to know if you are trying to fork a new process and run the script in the new process or if you want the script to run within the existing C++ program. – andy mango May 24 '20 at 16:10
  • Hi, I'm trying to run CPP script, at some point in the run, i want that the CPP test call a tcl script for run in, I have try this one - (Tcl_EvalFile(pInterp, "tclsh {\"C:/Users/avi/Desktop/Temp/test.tcl"}")); were not working for me. in addition, invoke a tcl shell and send a command that run the tcl scripts could be a good solution for me. thanks – user12755014 May 24 '20 at 16:22

1 Answers1

1

Depending on what you exactly want to do, you either run the Tcl script as a subprocess or embed a Tcl interpreter instance and use that. I'll assume that it is the latter.

Tcl is, apart from everything else, a (mainly) C library (and its header file is intentionally made compatible with being used from both C++ and Objective C). Thus:

#include <tcl.h>
#include <stdexcept>
#include <string>

public class TclInterpreter {
private:
    Tcl_Interp *interp;
public:
    TclInterpreter(const char *argv0 = nullptr) : interp(nullptr) {
        static bool initLib;
        if (!initLib) {
            Tcl_FindExecutable(argv0);
            initLib = true;
        }
        interp = Tcl_CreateInterp();
        if (!interp) throw new std::runtime_error("failed to initialise Tcl library");
    }

    ~TclInterpreter() {
        if (interp) Tcl_DeleteInterp(interp);
    }

    std::string evalFile(const std::string &filename) {
        // This next line is the CRITICAL one!
        int code = Tcl_EvalFile(interp, filename.c_str());

        if (code >= TCL_ERROR) {
            // You should make your own exception, but I've lost patience typing it out
            // This throws the exception message; it lasts until you use the interpreter again
            throw Tcl_GetStringResult(interp);
        }
        return std::string(Tcl_GetStringResult(interp));
    }
}

You'd then be able to call that a bit like this:

TclInterpreter interpreter(argv[0]); // << omit ‘argv[0]’ if you don't know it
std::string filename("my_file.tcl");
std::string result = interpreter.evalFile(filename);
std::cout << result << '\n';

You'd need to make sure that tcl.h is found when compiling, and you'd need to make sure that you link against libtcl.so/libtcl.dll/libtcl.dylib when linking. (The exact filename to link against may depend on exactly which version of Tcl you're wanting to link and what OS you're on.)


For a more sophisticated version of this that probably does a lot better job of error handling — the part I've sort-of glossed over rather above! — among other things (but is consequently more work to understand), see C++/Tcl. However, that doesn't seem to expose an evalFile method at this point so you'd need to run source my_file.tcl as a little scriptlet. (Tcl_EvalFile() is basically the implementation of the Tcl source command.)

Community
  • 1
  • 1
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • Standard Tcl's API will remain strict C. Not a chance of us changing that. We might use other languages in the implementation where that simplifies things for us. – Donal Fellows May 24 '20 at 18:36