diff --git a/common/command.cc b/common/command.cc index 5070bf9c..fd634df4 100644 --- a/common/command.cc +++ b/common/command.cc @@ -40,7 +40,7 @@ NEXTPNR_NAMESPACE_BEGIN -CommandHandler::CommandHandler(int argc, char **argv) : argc(argc), argv(argv) { log_files.push_back(stdout); } +CommandHandler::CommandHandler(int argc, char **argv) : argc(argc), argv(argv) { log_streams.clear(); } bool CommandHandler::parseOptions() { @@ -64,14 +64,14 @@ bool CommandHandler::parseOptions() bool CommandHandler::executeBeforeContext() { if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) + std::cerr << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")\n"; - std::cout << options << "\n"; + std::cerr << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) + std::cerr << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")\n"; return true; } @@ -84,7 +84,9 @@ po::options_description CommandHandler::getGeneralOptions() po::options_description general("General options"); general.add_options()("help,h", "show help"); general.add_options()("verbose,v", "verbose output"); - general.add_options()("quiet,q", "quiet mode, only errors displayed"); + general.add_options()("quiet,q", "quiet mode, only errors and warnings displayed"); + general.add_options()("log,l", po::value(), + "log file, all log messages are written to this file regardless of -q"); general.add_options()("debug", "debug output"); general.add_options()("force,f", "keep running after errors"); #ifndef NO_GUI @@ -128,7 +130,17 @@ void CommandHandler::setupContext(Context *ctx) } if (vm.count("quiet")) { - log_quiet_warnings = true; + log_streams.push_back(std::make_pair(&std::cerr, LogLevel::WARNING)); + } else { + log_streams.push_back(std::make_pair(&std::cerr, LogLevel::LOG)); + } + + if (vm.count("log")) { + std::string logfilename = vm["log"].as(); + logfile = std::ofstream(logfilename); + if (!logfile) + log_error("Failed to open log file '%s' for writing.\n", logfilename.c_str()); + log_streams.push_back(std::make_pair(&logfile, LogLevel::LOG)); } if (vm.count("force")) { @@ -144,7 +156,7 @@ void CommandHandler::setupContext(Context *ctx) int r; do { r = rand(); - } while(r == 0); + } while (r == 0); ctx->rngseed(r); } diff --git a/common/command.h b/common/command.h index 12f710f6..30e0e58b 100644 --- a/common/command.h +++ b/common/command.h @@ -66,6 +66,7 @@ class CommandHandler int argc; char **argv; ProjectHandler project; + std::ofstream logfile; }; NEXTPNR_NAMESPACE_END diff --git a/common/log.cc b/common/log.cc index 6b2d6065..19873148 100644 --- a/common/log.cc +++ b/common/log.cc @@ -32,18 +32,12 @@ NEXTPNR_NAMESPACE_BEGIN NPNR_NORETURN void logv_error(const char *format, va_list ap) NPNR_ATTRIBUTE(noreturn); -std::vector log_files; -std::vector log_streams; -FILE *log_errfile = NULL; +std::vector> log_streams; log_write_type log_write_function = nullptr; -bool log_error_stderr = false; -bool log_cmd_error_throw = false; -bool log_quiet_warnings = false; std::string log_last_error; void (*log_error_atexit)() = NULL; -// static bool next_print_log = false; static int log_newline_count = 0; std::string stringf(const char *fmt, ...) @@ -88,7 +82,7 @@ std::string vstringf(const char *fmt, va_list ap) return string; } -void logv(const char *format, va_list ap) +void logv(const char *format, va_list ap, LogLevel level = LogLevel::LOG) { // // Trim newlines from the beginning @@ -108,90 +102,50 @@ void logv(const char *format, va_list ap) else log_newline_count = str.size() - nnl_pos - 1; - for (auto f : log_files) - fputs(str.c_str(), f); - for (auto f : log_streams) - *f << str; + if (f.second <= level) + *f.first << str; if (log_write_function) log_write_function(str); } -void logv_info(const char *format, va_list ap) +void log_with_level(LogLevel level, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv(format, ap, level); + va_end(ap); +} + +void logv_prefixed(const char *prefix, const char *format, va_list ap, LogLevel level) { std::string message = vstringf(format, ap); - log_always("Info: %s", message.c_str()); + log_with_level(level, "%s%s", prefix, message.c_str()); log_flush(); } -void logv_warning(const char *format, va_list ap) -{ - std::string message = vstringf(format, ap); - - log_always("Warning: %s", message.c_str()); - log_flush(); -} - -void logv_warning_noprefix(const char *format, va_list ap) -{ - std::string message = vstringf(format, ap); - - log_always("%s", message.c_str()); -} - -void logv_error(const char *format, va_list ap) -{ -#ifdef EMSCRIPTEN - auto backup_log_files = log_files; -#endif - - if (log_errfile != NULL) - log_files.push_back(log_errfile); - - if (log_error_stderr) - for (auto &f : log_files) - if (f == stdout) - f = stderr; - - log_last_error = vstringf(format, ap); - log_always("ERROR: %s", log_last_error.c_str()); - log_flush(); - - if (log_error_atexit) - log_error_atexit(); - -#ifdef EMSCRIPTEN - log_files = backup_log_files; -#endif - throw log_execution_error_exception(); -} - void log_always(const char *format, ...) { va_list ap; va_start(ap, format); - logv(format, ap); + logv(format, ap, LogLevel::ALWAYS); va_end(ap); } void log(const char *format, ...) { - if (log_quiet_warnings) - return; va_list ap; va_start(ap, format); - logv(format, ap); + logv(format, ap, LogLevel::LOG); va_end(ap); } void log_info(const char *format, ...) { - if (log_quiet_warnings) - return; va_list ap; va_start(ap, format); - logv_info(format, ap); + logv_prefixed("Info: ", format, ap, LogLevel::INFO); va_end(ap); } @@ -199,15 +153,7 @@ void log_warning(const char *format, ...) { va_list ap; va_start(ap, format); - logv_warning(format, ap); - va_end(ap); -} - -void log_warning_noprefix(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_warning_noprefix(format, ap); + logv_prefixed("Warning: ", format, ap, LogLevel::WARNING); va_end(ap); } @@ -215,41 +161,26 @@ void log_error(const char *format, ...) { va_list ap; va_start(ap, format); - logv_error(format, ap); -} + logv_prefixed("ERROR: ", format, ap, LogLevel::ERROR); -void log_cmd_error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); + if (log_error_atexit) + log_error_atexit(); - if (log_cmd_error_throw) { - log_last_error = vstringf(format, ap); - log_always("ERROR: %s", log_last_error.c_str()); - log_flush(); - throw log_cmd_error_exception(); - } - - logv_error(format, ap); + throw log_execution_error_exception(); } void log_break() { - if (log_quiet_warnings) - return; if (log_newline_count < 2) - log_always("\n"); + log("\n"); if (log_newline_count < 2) - log_always("\n"); + log("\n"); } void log_flush() { - for (auto f : log_files) - fflush(f); - for (auto f : log_streams) - f->flush(); + f.first->flush(); } NEXTPNR_NAMESPACE_END diff --git a/common/log.h b/common/log.h index b5fddf53..de5aa85c 100644 --- a/common/log.h +++ b/common/log.h @@ -42,12 +42,18 @@ struct log_execution_error_exception { }; -extern std::vector log_files; -extern std::vector log_streams; -extern FILE *log_errfile; +enum class LogLevel +{ + LOG, + INFO, + WARNING, + ERROR, + ALWAYS +}; + +extern std::vector> log_streams; extern log_write_type log_write_function; -extern bool log_quiet_warnings; extern std::string log_last_error; extern void (*log_error_atexit)(); @@ -59,9 +65,7 @@ void log(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_info(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_warning(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); -void log_warning_noprefix(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); NPNR_NORETURN void log_error(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2), noreturn); -NPNR_NORETURN void log_cmd_error(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2), noreturn); void log_break(); void log_flush(); @@ -75,7 +79,6 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi NEXTPNR_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) #define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__) -#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) NEXTPNR_NAMESPACE_END diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 92812285..49c2d8d5 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -44,7 +44,6 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, ArchArgs args, initBasenameResource(); qRegisterMetaType(); - log_files.clear(); log_streams.clear(); setObjectName("BaseMainWindow");