OpenSTA/app/Main.cc

200 lines
5.1 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2024, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2018-09-28 17:54:21 +02:00
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2018-09-28 17:54:21 +02:00
2020-04-05 23:53:44 +02:00
#include "StaMain.hh"
#include "StaConfig.hh" // STA_VERSION
2020-04-05 20:35:51 +02:00
2018-09-28 17:54:21 +02:00
#include <stdio.h>
2020-12-26 17:29:43 +01:00
#include <cstdlib> // exit
2019-11-17 02:11:25 +01:00
#include <tcl.h>
#if TCL_READLINE
#include <tclreadline.h>
#endif
2020-04-05 20:35:51 +02:00
2020-04-05 23:53:44 +02:00
#include "Sta.hh"
2018-09-28 17:54:21 +02:00
2019-11-17 02:11:25 +01:00
namespace sta {
extern const char *tcl_inits[];
}
2020-11-30 16:05:50 +01:00
using std::string;
2018-09-28 17:54:21 +02:00
using sta::stringEq;
2019-11-17 02:11:25 +01:00
using sta::findCmdLineFlag;
2018-09-28 17:54:21 +02:00
using sta::Sta;
2019-11-17 02:11:25 +01:00
using sta::initSta;
using sta::evalTclInit;
using sta::sourceTclFile;
using sta::parseThreadsArg;
using sta::tcl_inits;
using sta::is_regular_file;
2018-09-28 17:54:21 +02:00
// Swig uses C linkage for init functions.
extern "C" {
extern int Sta_Init(Tcl_Interp *interp);
}
2019-11-17 02:11:25 +01:00
static int cmd_argc;
static char **cmd_argv;
static const char *init_filename = ".sta";
static void
showUsage(const char *prog,
const char *init_filename);
static int
tclAppInit(Tcl_Interp *interp);
static int
staTclAppInit(int argc,
char *argv[],
const char *init_filename,
Tcl_Interp *interp);
static void
2020-01-10 00:16:07 +01:00
initStaApp(int &argc,
2019-11-17 02:11:25 +01:00
char *argv[],
Tcl_Interp *interp);
2019-05-20 01:06:06 +02:00
2018-09-28 17:54:21 +02:00
int
2019-06-01 17:07:38 +02:00
main(int argc,
char *argv[])
2018-09-28 17:54:21 +02:00
{
if (argc == 2 && stringEq(argv[1], "-help")) {
2019-11-17 02:11:25 +01:00
showUsage(argv[0], init_filename);
2018-09-28 17:54:21 +02:00
return 0;
}
else if (argc == 2 && stringEq(argv[1], "-version")) {
2019-02-16 21:07:59 +01:00
printf("%s\n", STA_VERSION);
2018-09-28 17:54:21 +02:00
return 0;
}
else {
2019-11-17 02:11:25 +01:00
// Set argc to 1 so Tcl_Main doesn't source any files.
// Tcl_Main never returns.
#if 0
// It should be possible to pass argc/argv to staTclAppInit with
// a closure but I couldn't get the signature to match Tcl_AppInitProc.
Tcl_Main(1, argv, [=](Tcl_Interp *interp)
{ sta::staTclAppInit(argc, argv, interp);
return 1;
});
#else
// Workaround.
cmd_argc = argc;
cmd_argv = argv;
Tcl_Main(1, argv, tclAppInit);
#endif
2018-09-28 17:54:21 +02:00
return 0;
}
}
2019-11-17 02:11:25 +01:00
static int
tclAppInit(Tcl_Interp *interp)
{
return staTclAppInit(cmd_argc, cmd_argv, init_filename, interp);
}
// Tcl init executed inside Tcl_Main.
static int
staTclAppInit(int argc,
char *argv[],
const char *init_filename,
Tcl_Interp *interp)
{
// source init.tcl
if (Tcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
#if TCL_READLINE
if (Tclreadline_Init(interp) == TCL_ERROR)
return TCL_ERROR;
Tcl_StaticPackage(interp, "tclreadline", Tclreadline_Init, Tclreadline_SafeInit);
if (Tcl_EvalFile(interp, TCLRL_LIBRARY "/tclreadlineInit.tcl") != TCL_OK)
printf("Failed to load tclreadline.tcl\n");
#endif
2019-11-17 02:11:25 +01:00
initStaApp(argc, argv, interp);
if (!findCmdLineFlag(argc, argv, "-no_splash"))
Tcl_Eval(interp, "sta::show_splash");
if (!findCmdLineFlag(argc, argv, "-no_init")) {
const char *home = getenv("HOME");
if (home) {
string init_path = home;
init_path += "/";
init_path += init_filename;
if (is_regular_file(init_path.c_str()))
sourceTclFile(init_path.c_str(), true, true, interp);
}
2019-11-17 02:11:25 +01:00
}
bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit");
if (argc > 2
|| (argc > 1 && argv[1][0] == '-')) {
2019-11-17 02:11:25 +01:00
showUsage(argv[0], init_filename);
2020-12-25 00:54:26 +01:00
exit(1);
}
2019-11-17 02:11:25 +01:00
else {
if (argc == 2) {
char *cmd_file = argv[1];
if (cmd_file) {
2020-11-13 20:46:19 +01:00
int result = sourceTclFile(cmd_file, false, false, interp);
if (exit_after_cmd_file) {
int exit_code = (result == TCL_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
exit(exit_code);
}
2019-11-17 02:11:25 +01:00
}
}
}
#if TCL_READLINE
return Tcl_Eval(interp, "::tclreadline::Loop");
#else
2019-11-17 02:11:25 +01:00
return TCL_OK;
#endif
2019-11-17 02:11:25 +01:00
}
static void
2020-01-10 00:16:07 +01:00
initStaApp(int &argc,
2019-11-17 02:11:25 +01:00
char *argv[],
Tcl_Interp *interp)
{
initSta();
Sta *sta = new Sta;
Sta::setSta(sta);
sta->makeComponents();
sta->setTclInterp(interp);
int thread_count = parseThreadsArg(argc, argv);
sta->setThreadCount(thread_count);
// Define swig TCL commands.
Sta_Init(interp);
// Eval encoded sta TCL sources.
evalTclInit(interp, tcl_inits);
Tcl_Eval(interp, "init_sta_cmds");
2019-11-17 02:11:25 +01:00
}
static void
showUsage(const char *prog,
const char *init_filename)
{
printf("Usage: %s [-help] [-version] [-no_init] [-exit] cmd_file\n", prog);
printf(" -help show help and exit\n");
printf(" -version show version and exit\n");
printf(" -no_init do not read %s init file\n", init_filename);
printf(" -threads count|max use count threads\n");
printf(" -no_splash do not show the license splash at startup\n");
printf(" -exit exit after reading cmd_file\n");
printf(" cmd_file source cmd_file\n");
}