一、Openroad的函数入口
二、openroad的初始化源码解析
- 1.统一程序的本地化设置,确保数值解析、时间格式等行为在不同系统环境能够保持一致
std::array locales = {"en_US.UTF-8", "C.UTF-8", "C"};
for (auto locale : locales) {
if (std::setlocale(LC_ALL, locale) != nullptr) {
setenv("LC_ALL", locale, /* override */ 1);
break;
}
}
- 2.设置信号处理函数,其作用是为了记录程序发生错误是的信息
signal(SIGABRT, handler); //触发场景:内存分配失败,断言以及不可恢复的内部错误
signal(SIGBUS, handler); //触发场景:访问未物理映射的内存区域以及内存对其错误,硬件设备访问异常
signal(SIGFPE, handler); //整数除零,浮点运算一产(无穷打),位操作溢出
signal(SIGILL, handler); //执行cpu不支持的命令,代码段损坏,跳转到非代码段
signal(SIGSEGV, handler); //解引用空指针,数组访问越界,栈溢出(递归过深,或者是耗尽栈空间)
static void handler(int sig) //handle处理函数
{
if (fatal_error_in_progress) {
raise(sig);
} //目的:通过静态变量fatal_error_in_progress标记“正在处理崩溃”,避免处理信号期间再次触发其他信号导致无限递归。逻辑:若标记已置位,直接重新发送信号(raise(sig))触发系统默认处理流程。
fatal_error_in_progress = 1;
std::cerr << "Signal " << sig << " received\n"; //打印触发崩溃的具体信号编号(如SIGSEGV对应11),明确错误类型。
std::cerr << "Stack trace:\n";
std::cerr << boost::stacktrace::stacktrace(); //使用Boost库的stacktrace模块输出当前线程的完整调用栈。
signal(sig, SIG_DFL); //signal(sig, SIG_DFL)将信号处理重置为系统默认行为(如SIGSEGV默认终止进程并生成core dump)。
raise(sig); //raise(sig)主动发送信号,此时系统按默认方式终止进程。
}
if (argc == 2 && stringEq(argv[1], "-help")) {
showUsage(argv[0], init_filename);
return 0;
} //hlep option终端打印可以使用的option信息
if (argc == 2 && stringEq(argv[1], "-version")) {
printf("%s %s\n",
ord::OpenRoad::getVersion(),
ord::OpenRoad::getGitDescribe());
return 0;
} //获取openroad版本号以及git描述信息
log_filename = findCmdLineKey(argc, argv, "-log");
if (log_filename) {
remove(log_filename);
} //log地址重置
metrics_filename = findCmdLineKey(argc, argv, "-metrics");
if (metrics_filename) {
remove(metrics_filename);
} //未知
no_settings = findCmdLineFlag(argc, argv, "-no_settings");
minimize = findCmdLineFlag(argc, argv, "-minimize");
cmd_argc = argc; //参数个数
cmd_argv = argv; //传递终端参数数组指针
Tcl_Main(1, argv, ord::tclAppInit); //tcl处理函数
int ord::tclAppInit(Tcl_Interp* interp)
{
the_tech_and_design.tech = std::make_unique<ord::Tech>(interp);
the_tech_and_design.design
= std::make_unique<ord::Design>(the_tech_and_design.tech.get());
ord::OpenRoad::setOpenRoad(the_tech_and_design.design->getOpenRoad()); //初始化构造tech这个单例类,tech类中构造openroad
// This is to enable Design.i where a design arg can be
// retrieved from the interpreter. This is necessary for
// cases with more than one interpreter (ie more than one Design).
// This should replace the use of the singleton OpenRoad::openRoad().
Tcl_SetAssocData(interp, "design", nullptr, the_tech_and_design.design.get());//将自定义c++数据结构在tcl解析器中与design字符串绑定,可以使得tcl获取简单的oop功能(如:$design get_core_area)
return ord::tclInit(interp);
}
int ord::tclInit(Tcl_Interp* interp)
{
return tclAppInit(cmd_argc, cmd_argv, init_filename, interp); //上一个函数返回值的中转
}
static int tclAppInit(int& argc,
char* argv[],
const char* init_filename,
Tcl_Interp* interp)
{
bool exit_after_cmd_file = false;
// first check if gui was requested and launch.
// gui will call this function again as part of setup
// ensuring the else {} will be utilized to initialize tcl and OR.
if (findCmdLineFlag(argc, argv, "-gui")) {
// gobble up remaining -gui flags if present, since this could result in
// second invocation of the GUI
while (findCmdLineFlag(argc, argv, "-gui")) {
;
}
gui::startGui(argc, argv, interp, "", true, !no_settings, minimize); //开启gui功能
} else { //不开启gui功能
// init tcl
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit");
ord::initOpenRoad(interp, log_filename, metrics_filename);
bool no_splash = findCmdLineFlag(argc, argv, "-no_splash");
if (!no_splash) {
showSplash(); //显示openroad终端的tile说明
}
//线程数目设置
const char* threads = findCmdLineKey(argc, argv, "-threads");
if (threads) {
ord::OpenRoad::openRoad()->setThreadCount(threads, !no_splash);
} else {
// set to default number of threads
ord::OpenRoad::openRoad()->setThreadCount(
ord::OpenRoad::openRoad()->getThreadCount(), false);
}
const bool gui_enabled = gui::Gui::enabled();
if (argc > 2 || (argc > 1 && argv[1][0] == '-')) {
showUsage(argv[0], init_filename);
exit(1);
} else {
if (argc == 2) {
char* cmd_file = argv[1];
if (cmd_file) {
if (!gui_enabled) {
int result = sourceTclFile(cmd_file, false, false, interp); //执行tcl文件,其底层是使用tcl来解析tcl文件,相当于source tclfile命令
if (exit_after_cmd_file) {
int exit_code = (result == TCL_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
exit(exit_code);
}
} else {
// need to delay loading of file until after GUI is completed
// initialized
gui::Gui::get()->addRestoreStateCommand(
fmt::format("source {{{}}}", cmd_file));
if (exit_after_cmd_file) {
gui::Gui::get()->addRestoreStateCommand("exit");
}
}
}
}
}
}
#ifdef ENABLE_READLINE //循环读入终端输入命令
if (!gui::Gui::enabled() && !exit_after_cmd_file) {
return tclReadlineInit(interp);
}
#endif
return TCL_OK;