From ea91f189a3db214fbb5c747ca1e6a24b7c3e5494 Mon Sep 17 00:00:00 2001 From: anonkey <6380129+anonkey@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:18:33 +0200 Subject: [PATCH 1/2] cli(tcl): add ability to pass argument to tcl script from cli --- CHANGELOG | 4 ++++ kernel/driver.cc | 52 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee5f6b43d..eac68b1ed 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ List of major changes and improvements between releases Yosys 0.34 .. Yosys 0.35-dev -------------------------- +* New commands and options + - Added option "--" to pass arguments down to tcl when using -c option. + - Added ability on MacOS and Windows to pass options after arguments on cli. + Yosys 0.33 .. Yosys 0.34 -------------------------- diff --git a/kernel/driver.cc b/kernel/driver.cc index ef8e77924..661400e7a 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -49,39 +49,47 @@ # include #endif -#if !defined(_WIN32) || defined(__MINGW32__) -# include -#else char *optarg; -int optind = 1, optcur = 1; +int optind = 1, optcur = 1, optopt = 0; int getopt(int argc, char **argv, const char *optstring) { - if (optind >= argc || argv[optind][0] != '-') + if (optind >= argc) return -1; + if (argv[optind][0] != '-') { + optopt = 1; + optarg = argv[optind++]; + return optopt; + } + bool takes_arg = false; - int opt = argv[optind][optcur]; + optopt = argv[optind][optcur]; + + if (optopt == '-') { + ++optind; + return -1; + } + for (int i = 0; optstring[i]; i++) - if (opt == optstring[i] && optstring[i + 1] == ':') + if (optopt == optstring[i] && optstring[i + 1] == ':') takes_arg = true; if (!takes_arg) { if (argv[optind][++optcur] == 0) optind++, optcur = 1; - return opt; + return optopt; } if (argv[optind][++optcur]) { optarg = argv[optind++] + optcur; optcur = 1; - return opt; + return optopt; } optarg = argv[++optind]; optind++, optcur = 1; - return opt; + return optopt; } -#endif USING_YOSYS_NAMESPACE @@ -215,6 +223,7 @@ int main(int argc, char **argv) std::string backend_command = "auto"; std::vector vlog_defines; std::vector passes_commands; + std::vector frontend_files; std::vector plugin_filenames; std::string output_filename = ""; std::string scriptfile = ""; @@ -509,6 +518,9 @@ int main(int argc, char **argv) case 'C': run_tcl_shell = true; break; + case '\001': + frontend_files.push_back(optarg); + break; default: fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); exit(1); @@ -561,17 +573,27 @@ int main(int argc, char **argv) run_pass(vdef_cmd); } - while (optind < argc) - if (run_frontend(argv[optind++], frontend_command)) + for (auto it = frontend_files.begin(); it != frontend_files.end(); ++it) { + if (run_frontend((*it).c_str(), frontend_command)) run_shell = false; + } if (!topmodule.empty()) run_pass("hierarchy -top " + topmodule); - if (!scriptfile.empty()) { if (scriptfile_tcl) { #ifdef YOSYS_ENABLE_TCL - if (Tcl_EvalFile(yosys_get_tcl_interp(), scriptfile.c_str()) != TCL_OK) + int tcl_argc = argc - optind; + std::vector script_args; + Tcl_Interp *interp = yosys_get_tcl_interp(); + for (int i = optind; i < argc; ++i) + script_args.push_back(Tcl_NewStringObj(argv[i], strlen(argv[i]))); + + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(tcl_argc), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(tcl_argc, script_args.data()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(scriptfile.c_str(), scriptfile.length()), 0); + + if (Tcl_EvalFile(interp, scriptfile.c_str()) != TCL_OK) log_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); #else log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n"); From d415b4d98a0ac7d5177e3b5844477e8460bfa862 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 6 Nov 2023 16:40:13 +0100 Subject: [PATCH 2/2] cli: Cleanups for tcl argument handling * Keep the previous behavior when no tcl script is used * Do not treat "-" as a flag but as a positional argument * Keep including as it's also used for other functions (at least for the emscripten build) * Move the custom getopt implementation into the Yosys namespace to avoid potential collisions --- kernel/driver.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 661400e7a..c779611e0 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -49,6 +49,12 @@ # include #endif +#if !defined(_WIN32) || defined(__MINGW32__) +# include +#endif + +USING_YOSYS_NAMESPACE + char *optarg; int optind = 1, optcur = 1, optopt = 0; int getopt(int argc, char **argv, const char *optstring) @@ -56,7 +62,7 @@ int getopt(int argc, char **argv, const char *optstring) if (optind >= argc) return -1; - if (argv[optind][0] != '-') { + if (argv[optind][0] != '-' || argv[optind][1] == 0) { optopt = 1; optarg = argv[optind++]; return optopt; @@ -91,9 +97,6 @@ int getopt(int argc, char **argv, const char *optstring) return optopt; } - -USING_YOSYS_NAMESPACE - #ifdef EMSCRIPTEN # include # include @@ -573,6 +576,12 @@ int main(int argc, char **argv) run_pass(vdef_cmd); } + if (scriptfile.empty() || !scriptfile_tcl) { + // Without a TCL script, arguments following '--' are also treated as frontend files + for (int i = optind; i < argc; ++i) + frontend_files.push_back(argv[i]); + } + for (auto it = frontend_files.begin(); it != frontend_files.end(); ++it) { if (run_frontend((*it).c_str(), frontend_command)) run_shell = false;