/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup creator */ #ifndef WITH_PYTHON_MODULE # include # include # include # include "MEM_guardedalloc.h" # include "CLG_log.h" # ifdef WIN32 # include "BLI_winstuff.h" # endif # include "BLI_args.h" # include "BLI_fileops.h" # include "BLI_listbase.h" # include "BLI_mempool.h" # include "BLI_path_util.h" # include "BLI_string.h" # include "BLI_string_utf8.h" # include "BLI_system.h" # include "BLI_threads.h" # include "BLI_utildefines.h" # include "BLO_readfile.h" /* only for BLO_has_bfile_extension */ # include "BKE_blender_version.h" # include "BKE_context.h" # include "BKE_global.h" # include "BKE_image_format.h" # include "BKE_lib_id.h" # include "BKE_main.h" # include "BKE_report.h" # include "BKE_scene.h" # include "BKE_sound.h" # include "GPU_context.h" # ifdef WITH_FFMPEG # include "IMB_imbuf.h" # endif # ifdef WITH_PYTHON # include "BPY_extern_python.h" # include "BPY_extern_run.h" # endif # include "RE_engine.h" # include "RE_pipeline.h" # include "ED_datafiles.h" # include "WM_api.h" # ifdef WITH_LIBMV # include "libmv-capi.h" # endif # ifdef WITH_CYCLES_LOGGING # include "CCL_api.h" # endif # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" # include "DEG_depsgraph_debug.h" # include "WM_types.h" # include "creator_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Utility String Parsing * \{ */ static bool parse_int_relative(const char *str, const char *str_end_test, int pos, int neg, int *r_value, const char **r_err_msg) { char *str_end = NULL; long value; errno = 0; switch (*str) { case '+': value = pos + strtol(str + 1, &str_end, 10); break; case '-': value = (neg - strtol(str + 1, &str_end, 10)) + 1; break; default: value = strtol(str, &str_end, 10); break; } if (*str_end != '\0' && (str_end != str_end_test)) { static const char *msg = "not a number"; *r_err_msg = msg; return false; } if ((errno == ERANGE) || ((value < INT_MIN) || (value > INT_MAX))) { static const char *msg = "exceeds range"; *r_err_msg = msg; return false; } *r_value = (int)value; return true; } static const char *parse_int_range_sep_search(const char *str, const char *str_end_test) { const char *str_end_range = NULL; if (str_end_test) { str_end_range = memchr(str, '.', (str_end_test - str) - 1); if (str_end_range && (str_end_range[1] != '.')) { str_end_range = NULL; } } else { str_end_range = strstr(str, ".."); if (str_end_range && (str_end_range[2] == '\0')) { str_end_range = NULL; } } return str_end_range; } /** * Parse a number as a range, eg: `1..4`. * * The \a str_end_range argument is a result of #parse_int_range_sep_search. */ static bool parse_int_range_relative(const char *str, const char *str_end_range, const char *str_end_test, int pos, int neg, int r_value_range[2], const char **r_err_msg) { if (parse_int_relative(str, str_end_range, pos, neg, &r_value_range[0], r_err_msg) && parse_int_relative( str_end_range + 2, str_end_test, pos, neg, &r_value_range[1], r_err_msg)) { return true; } return false; } static bool parse_int_relative_clamp(const char *str, const char *str_end_test, int pos, int neg, int min, int max, int *r_value, const char **r_err_msg) { if (parse_int_relative(str, str_end_test, pos, neg, r_value, r_err_msg)) { CLAMP(*r_value, min, max); return true; } return false; } static bool parse_int_range_relative_clamp(const char *str, const char *str_end_range, const char *str_end_test, int pos, int neg, int min, int max, int r_value_range[2], const char **r_err_msg) { if (parse_int_range_relative( str, str_end_range, str_end_test, pos, neg, r_value_range, r_err_msg)) { CLAMP(r_value_range[0], min, max); CLAMP(r_value_range[1], min, max); return true; } return false; } /** * No clamping, fails with any number outside the range. */ static bool parse_int_strict_range(const char *str, const char *str_end_test, const int min, const int max, int *r_value, const char **r_err_msg) { char *str_end = NULL; long value; errno = 0; value = strtol(str, &str_end, 10); if (*str_end != '\0' && (str_end != str_end_test)) { static const char *msg = "not a number"; *r_err_msg = msg; return false; } if ((errno == ERANGE) || ((value < min) || (value > max))) { static const char *msg = "exceeds range"; *r_err_msg = msg; return false; } *r_value = (int)value; return true; } static bool parse_int(const char *str, const char *str_end_test, int *r_value, const char **r_err_msg) { return parse_int_strict_range(str, str_end_test, INT_MIN, INT_MAX, r_value, r_err_msg); } static bool parse_int_clamp(const char *str, const char *str_end_test, int min, int max, int *r_value, const char **r_err_msg) { if (parse_int(str, str_end_test, r_value, r_err_msg)) { CLAMP(*r_value, min, max); return true; } return false; } # if 0 /** * Version of #parse_int_relative_clamp * that parses a comma separated list of numbers. */ static int *parse_int_relative_clamp_n( const char *str, int pos, int neg, int min, int max, int *r_value_len, const char **r_err_msg) { const char sep = ','; int len = 1; for (int i = 0; str[i]; i++) { if (str[i] == sep) { len++; } } int *values = MEM_mallocN(sizeof(*values) * len, __func__); int i = 0; while (true) { const char *str_end = strchr(str, sep); if (ELEM(*str, sep, '\0')) { static const char *msg = "incorrect comma use"; *r_err_msg = msg; goto fail; } else if (parse_int_relative_clamp(str, str_end, pos, neg, min, max, &values[i], r_err_msg)) { i++; } else { goto fail; /* error message already set */ } if (str_end) { /* next */ str = str_end + 1; } else { /* finished */ break; } } *r_value_len = i; return values; fail: MEM_freeN(values); return NULL; } # endif /** * Version of #parse_int_relative_clamp & #parse_int_range_relative_clamp * that parses a comma separated list of numbers. * * \note single values are evaluated as a range with matching start/end. */ static int (*parse_int_range_relative_clamp_n(const char *str, int pos, int neg, int min, int max, int *r_value_len, const char **r_err_msg))[2] { const char sep = ','; int len = 1; for (int i = 0; str[i]; i++) { if (str[i] == sep) { len++; } } int(*values)[2] = MEM_mallocN(sizeof(*values) * len, __func__); int i = 0; while (true) { const char *str_end_range; const char *str_end = strchr(str, sep); if (ELEM(*str, sep, '\0')) { static const char *msg = "incorrect comma use"; *r_err_msg = msg; goto fail; } else if ((str_end_range = parse_int_range_sep_search(str, str_end)) ? parse_int_range_relative_clamp( str, str_end_range, str_end, pos, neg, min, max, values[i], r_err_msg) : parse_int_relative_clamp( str, str_end, pos, neg, min, max, &values[i][0], r_err_msg)) { if (str_end_range == NULL) { values[i][1] = values[i][0]; } i++; } else { goto fail; /* error message already set */ } if (str_end) { /* next */ str = str_end + 1; } else { /* finished */ break; } } *r_value_len = i; return values; fail: MEM_freeN(values); return NULL; } /** \} */ /* -------------------------------------------------------------------- */ /** \name Utilities Python Context Macro (#BPY_CTX_SETUP) * \{ */ # ifdef WITH_PYTHON struct BlendePyContextStore { wmWindowManager *wm; Scene *scene; wmWindow *win; bool has_win; }; static void arg_py_context_backup(bContext *C, struct BlendePyContextStore *c_py, const char *script_id) { c_py->wm = CTX_wm_manager(C); c_py->scene = CTX_data_scene(C); c_py->has_win = !BLI_listbase_is_empty(&c_py->wm->windows); if (c_py->has_win) { c_py->win = CTX_wm_window(C); CTX_wm_window_set(C, c_py->wm->windows.first); } else { c_py->win = NULL; fprintf(stderr, "Python script \"%s\" " "running with missing context data.\n", script_id); } } static void arg_py_context_restore(bContext *C, struct BlendePyContextStore *c_py) { /* script may load a file, check old data is valid before using */ if (c_py->has_win) { if ((c_py->win == NULL) || ((BLI_findindex(&G_MAIN->wm, c_py->wm) != -1) && (BLI_findindex(&c_py->wm->windows, c_py->win) != -1))) { CTX_wm_window_set(C, c_py->win); } } if ((c_py->scene == NULL) || BLI_findindex(&G_MAIN->scenes, c_py->scene) != -1) { CTX_data_scene_set(C, c_py->scene); } } /* macro for context setup/reset */ # define BPY_CTX_SETUP(_cmd) \ { \ struct BlendePyContextStore py_c; \ arg_py_context_backup(C, &py_c, argv[1]); \ { \ _cmd; \ } \ arg_py_context_restore(C, &py_c); \ } \ ((void)0) # endif /* WITH_PYTHON */ /** \} */ /* -------------------------------------------------------------------- */ /** \name Handle Argument Callbacks * * \note Doc strings here are used in differently: * * - The `--help` message. * - The man page (for Unix systems), * see: `doc/manpage/blender.1.py` * - Parsed and extracted for the manual, * which converts our ad-hoc formatting to reStructuredText. * see: https://docs.blender.org/manual/en/dev/advanced/command_line.html * * \{ */ static void print_version_full(void) { printf("Blender %s\n", BKE_blender_version_string()); # ifdef BUILD_DATE printf("\tbuild date: %s\n", build_date); printf("\tbuild time: %s\n", build_time); printf("\tbuild commit date: %s\n", build_commit_date); printf("\tbuild commit time: %s\n", build_commit_time); printf("\tbuild hash: %s\n", build_hash); printf("\tbuild platform: %s\n", build_platform); printf("\tbuild type: %s\n", build_type); printf("\tbuild c flags: %s\n", build_cflags); printf("\tbuild c++ flags: %s\n", build_cxxflags); printf("\tbuild link flags: %s\n", build_linkflags); printf("\tbuild system: %s\n", build_system); # endif } static void print_version_short(void) { # ifdef BUILD_DATE /* NOTE: We include built time since sometimes we need to tell broken from * working built of the same hash. */ printf("Blender %s (hash %s built %s %s)\n", BKE_blender_version_string(), build_hash, build_date, build_time); # else printf("Blender %s\n", BKE_blender_version_string()); # endif } static const char arg_handle_print_version_doc[] = "\n\t" "Print Blender version and exit."; static int arg_handle_print_version(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { print_version_full(); exit(0); return 0; } static const char arg_handle_print_help_doc[] = "\n\t" "Print this help text and exit."; static const char arg_handle_print_help_doc_win32[] = "\n\t" "Print this help text and exit (Windows only)."; static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), void *data) { bArgs *ba = (bArgs *)data; printf("Blender %s\n", BKE_blender_version_string()); printf("Usage: blender [args ...] [file] [args ...]\n\n"); printf("Render Options:\n"); BLI_args_print_arg_doc(ba, "--background"); BLI_args_print_arg_doc(ba, "--render-anim"); BLI_args_print_arg_doc(ba, "--scene"); BLI_args_print_arg_doc(ba, "--render-frame"); BLI_args_print_arg_doc(ba, "--frame-start"); BLI_args_print_arg_doc(ba, "--frame-end"); BLI_args_print_arg_doc(ba, "--frame-jump"); BLI_args_print_arg_doc(ba, "--render-output"); BLI_args_print_arg_doc(ba, "--engine"); BLI_args_print_arg_doc(ba, "--threads"); printf("\n"); printf("Format Options:\n"); BLI_args_print_arg_doc(ba, "--render-format"); BLI_args_print_arg_doc(ba, "--use-extension"); printf("\n"); printf("Animation Playback Options:\n"); BLI_args_print_arg_doc(ba, "-a"); printf("\n"); printf("Window Options:\n"); BLI_args_print_arg_doc(ba, "--window-border"); BLI_args_print_arg_doc(ba, "--window-fullscreen"); BLI_args_print_arg_doc(ba, "--window-geometry"); BLI_args_print_arg_doc(ba, "--window-maximized"); BLI_args_print_arg_doc(ba, "--start-console"); BLI_args_print_arg_doc(ba, "--no-native-pixels"); BLI_args_print_arg_doc(ba, "--no-window-focus"); printf("\n"); printf("Python Options:\n"); BLI_args_print_arg_doc(ba, "--enable-autoexec"); BLI_args_print_arg_doc(ba, "--disable-autoexec"); printf("\n"); BLI_args_print_arg_doc(ba, "--python"); BLI_args_print_arg_doc(ba, "--python-text"); BLI_args_print_arg_doc(ba, "--python-expr"); BLI_args_print_arg_doc(ba, "--python-console"); BLI_args_print_arg_doc(ba, "--python-exit-code"); BLI_args_print_arg_doc(ba, "--python-use-system-env"); BLI_args_print_arg_doc(ba, "--addons"); printf("\n"); printf("Logging Options:\n"); BLI_args_print_arg_doc(ba, "--log"); BLI_args_print_arg_doc(ba, "--log-level"); BLI_args_print_arg_doc(ba, "--log-show-basename"); BLI_args_print_arg_doc(ba, "--log-show-backtrace"); BLI_args_print_arg_doc(ba, "--log-show-timestamp"); BLI_args_print_arg_doc(ba, "--log-file"); printf("\n"); printf("Debug Options:\n"); BLI_args_print_arg_doc(ba, "--debug"); BLI_args_print_arg_doc(ba, "--debug-value"); printf("\n"); BLI_args_print_arg_doc(ba, "--debug-events"); # ifdef WITH_FFMPEG BLI_args_print_arg_doc(ba, "--debug-ffmpeg"); # endif BLI_args_print_arg_doc(ba, "--debug-handlers"); # ifdef WITH_LIBMV BLI_args_print_arg_doc(ba, "--debug-libmv"); # endif # ifdef WITH_CYCLES_LOGGING BLI_args_print_arg_doc(ba, "--debug-cycles"); # endif BLI_args_print_arg_doc(ba, "--debug-memory"); BLI_args_print_arg_doc(ba, "--debug-jobs"); BLI_args_print_arg_doc(ba, "--debug-python"); BLI_args_print_arg_doc(ba, "--debug-depsgraph"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-eval"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-build"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-tag"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-no-threads"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-time"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-pretty"); BLI_args_print_arg_doc(ba, "--debug-depsgraph-uuid"); BLI_args_print_arg_doc(ba, "--debug-ghost"); BLI_args_print_arg_doc(ba, "--debug-wintab"); BLI_args_print_arg_doc(ba, "--debug-gpu"); BLI_args_print_arg_doc(ba, "--debug-gpu-force-workarounds"); BLI_args_print_arg_doc(ba, "--debug-gpu-disable-ssbo"); BLI_args_print_arg_doc(ba, "--debug-wm"); # ifdef WITH_XR_OPENXR BLI_args_print_arg_doc(ba, "--debug-xr"); BLI_args_print_arg_doc(ba, "--debug-xr-time"); # endif BLI_args_print_arg_doc(ba, "--debug-all"); BLI_args_print_arg_doc(ba, "--debug-io"); printf("\n"); BLI_args_print_arg_doc(ba, "--debug-fpe"); BLI_args_print_arg_doc(ba, "--debug-exit-on-error"); BLI_args_print_arg_doc(ba, "--disable-crash-handler"); BLI_args_print_arg_doc(ba, "--disable-abort-handler"); BLI_args_print_arg_doc(ba, "--verbose"); printf("\n"); printf("Misc Options:\n"); BLI_args_print_arg_doc(ba, "--open-last"); BLI_args_print_arg_doc(ba, "--app-template"); BLI_args_print_arg_doc(ba, "--factory-startup"); BLI_args_print_arg_doc(ba, "--enable-event-simulate"); printf("\n"); BLI_args_print_arg_doc(ba, "--env-system-datafiles"); BLI_args_print_arg_doc(ba, "--env-system-scripts"); BLI_args_print_arg_doc(ba, "--env-system-python"); printf("\n"); BLI_args_print_arg_doc(ba, "-noaudio"); BLI_args_print_arg_doc(ba, "-setaudio"); printf("\n"); BLI_args_print_arg_doc(ba, "--help"); BLI_args_print_arg_doc(ba, "/?"); /* WIN32 only (ignored for non-win32) */ BLI_args_print_arg_doc(ba, "-R"); BLI_args_print_arg_doc(ba, "-r"); BLI_args_print_arg_doc(ba, "--version"); BLI_args_print_arg_doc(ba, "--"); // printf("\n"); // printf("Experimental Features:\n"); /* Other options _must_ be last (anything not handled will show here). * * Note that it's good practice for this to remain empty, * nevertheless print if any exist. */ if (BLI_args_has_other_doc(ba)) { printf("\n"); printf("Other Options:\n"); BLI_args_print_other_doc(ba); } printf("\n"); printf("Argument Parsing:\n"); printf("\tArguments must be separated by white space, eg:\n"); printf("\t# blender -ba test.blend\n"); printf("\t...will exit since '-ba' is an unknown argument.\n"); printf("Argument Order:\n"); printf("\tArguments are executed in the order they are given. eg:\n"); printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n"); printf( "\t...will not render to '/tmp' because '--render-frame 1' renders before the output path " "is set.\n"); printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n"); printf( "\t...will not render to '/tmp' because loading the blend-file overwrites the render output " "that was set.\n"); printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n"); printf("\t...works as expected.\n\n"); printf("Environment Variables:\n"); printf(" $BLENDER_USER_RESOURCES Top level directory for user files.\n"); printf(" (other 'BLENDER_USER_*' variables override when set).\n"); printf(" $BLENDER_USER_CONFIG Directory for user configuration files.\n"); printf(" $BLENDER_USER_SCRIPTS Directory for user scripts.\n"); printf(" $BLENDER_USER_DATAFILES Directory for user data files (icons, translations, ..).\n"); printf("\n"); printf(" $BLENDER_SYSTEM_RESOURCES Top level directory for system files.\n"); printf(" (other 'BLENDER_SYSTEM_*' variables override when set).\n"); printf(" $BLENDER_SYSTEM_SCRIPTS Directory for system wide scripts.\n"); printf(" $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n"); printf(" $BLENDER_SYSTEM_PYTHON Directory for system Python libraries.\n"); # ifdef WITH_OCIO printf(" $OCIO Path to override the OpenColorIO config file.\n"); # endif # ifdef WIN32 printf(" $TEMP Store temporary files here.\n"); # else printf(" $TMP or $TMPDIR Store temporary files here.\n"); # endif exit(0); return 0; } static const char arg_handle_arguments_end_doc[] = "\n\t" "End option processing, following arguments passed unchanged. Access via Python's " "'sys.argv'."; static int arg_handle_arguments_end(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { return -1; } /* only to give help message */ # ifndef WITH_PYTHON_SECURITY /* default */ # define PY_ENABLE_AUTO ", (default)" # define PY_DISABLE_AUTO "" # else # define PY_ENABLE_AUTO "" # define PY_DISABLE_AUTO ", (compiled as non-standard default)" # endif static const char arg_handle_python_set_doc_enable[] = "\n\t" "Enable automatic Python script execution" PY_ENABLE_AUTO "."; static const char arg_handle_python_set_doc_disable[] = "\n\t" "Disable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO "."; # undef PY_ENABLE_AUTO # undef PY_DISABLE_AUTO static int arg_handle_python_set(int UNUSED(argc), const char **UNUSED(argv), void *data) { if ((bool)data) { G.f |= G_FLAG_SCRIPT_AUTOEXEC; } else { G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; } G.f |= G_FLAG_SCRIPT_OVERRIDE_PREF; return 0; } static const char arg_handle_crash_handler_disable_doc[] = "\n\t" "Disable the crash handler."; static int arg_handle_crash_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { app_state.signal.use_crash_handler = false; return 0; } static const char arg_handle_abort_handler_disable_doc[] = "\n\t" "Disable the abort handler."; static int arg_handle_abort_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { app_state.signal.use_abort_handler = false; return 0; } static void clog_abort_on_error_callback(void *fp) { BLI_system_backtrace(fp); fflush(fp); abort(); } static const char arg_handle_debug_exit_on_error_doc[] = "\n\t" "Immediately exit when internal errors are detected."; static int arg_handle_debug_exit_on_error(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { MEM_enable_fail_on_memleak(); CLG_error_fn_set(clog_abort_on_error_callback); return 0; } static const char arg_handle_background_mode_set_doc[] = "\n\t" "Run in background (often used for UI-less rendering)."; static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { print_version_short(); G.background = 1; return 0; } static const char arg_handle_log_level_set_doc[] = "\n" "\tSet the logging verbosity level (higher for more details) defaults to 1,\n" "\tuse -1 to log all levels."; static int arg_handle_log_level_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--log-level"; if (argc > 1) { const char *err_msg = NULL; if (!parse_int_clamp(argv[1], NULL, -1, INT_MAX, &G.log.level, &err_msg)) { printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]); } else { if (G.log.level == -1) { G.log.level = INT_MAX; } CLG_level_set(G.log.level); } return 1; } printf("\nError: '%s' no args given.\n", arg_id); return 0; } static const char arg_handle_log_show_basename_set_doc[] = "\n\t" "Only show file name in output (not the leading path)."; static int arg_handle_log_show_basename_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { CLG_output_use_basename_set(true); return 0; } static const char arg_handle_log_show_backtrace_set_doc[] = "\n\t" "Show a back trace for each log message (debug builds only)."; static int arg_handle_log_show_backtrace_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { /* Ensure types don't become incompatible. */ void (*fn)(FILE * fp) = BLI_system_backtrace; CLG_backtrace_fn_set((void (*)(void *))fn); return 0; } static const char arg_handle_log_show_timestamp_set_doc[] = "\n\t" "Show a timestamp for each log message in seconds since start."; static int arg_handle_log_show_timestamp_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { CLG_output_use_timestamp_set(true); return 0; } static const char arg_handle_log_file_set_doc[] = "\n" "\tSet a file to output the log to."; static int arg_handle_log_file_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--log-file"; if (argc > 1) { errno = 0; FILE *fp = BLI_fopen(argv[1], "w"); if (fp == NULL) { const char *err_msg = errno ? strerror(errno) : "unknown"; printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]); } else { if (UNLIKELY(G.log.file != NULL)) { fclose(G.log.file); } G.log.file = fp; CLG_output_set(G.log.file); } return 1; } printf("\nError: '%s' no args given.\n", arg_id); return 0; } static const char arg_handle_log_set_doc[] = "\n" "\tEnable logging categories, taking a single comma separated argument.\n" "\tMultiple categories can be matched using a '.*' suffix,\n" "\tso '--log \"wm.*\"' logs every kind of window-manager message.\n" "\tSub-string can be matched using a '*' prefix and suffix,\n" "\tso '--log \"*undo*\"' logs every kind of undo-related message.\n" "\tUse \"^\" prefix to ignore, so '--log \"*,^wm.operator.*\"' logs all except for " "'wm.operators.*'\n" "\tUse \"*\" to log everything."; static int arg_handle_log_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--log"; if (argc > 1) { const char *str_step = argv[1]; while (*str_step) { const char *str_step_end = strchr(str_step, ','); int str_step_len = str_step_end ? (str_step_end - str_step) : strlen(str_step); if (str_step[0] == '^') { CLG_type_filter_exclude(str_step + 1, str_step_len - 1); } else { CLG_type_filter_include(str_step, str_step_len); } if (str_step_end) { /* Typically only be one, but don't fail on multiple. */ while (*str_step_end == ',') { str_step_end++; } str_step = str_step_end; } else { break; } } return 1; } printf("\nError: '%s' no args given.\n", arg_id); return 0; } static const char arg_handle_debug_mode_set_doc[] = "\n" "\tTurn debugging on.\n" "\n" "\t* Enables memory error detection\n" "\t* Disables mouse grab (to interact with a debugger in some cases)\n" "\t* Keeps Python's 'sys.stdin' rather than setting it to None"; static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data) { G.debug |= G_DEBUG; /* std output printf's */ printf("Blender %s\n", BKE_blender_version_string()); MEM_set_memory_debug(); # ifndef NDEBUG BLI_mempool_set_memory_debug(); # endif # ifdef WITH_BUILDINFO printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type); # endif BLI_args_print(data); return 0; } # ifdef WITH_FFMPEG static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] = "\n\t" "Enable debug messages from FFmpeg library."; # endif # ifdef WITH_FREESTYLE static const char arg_handle_debug_mode_generic_set_doc_freestyle[] = "\n\t" "Enable debug messages for Freestyle."; # endif static const char arg_handle_debug_mode_generic_set_doc_python[] = "\n\t" "Enable debug messages for Python."; static const char arg_handle_debug_mode_generic_set_doc_events[] = "\n\t" "Enable debug messages for the event system."; static const char arg_handle_debug_mode_generic_set_doc_handlers[] = "\n\t" "Enable debug messages for event handling."; static const char arg_handle_debug_mode_generic_set_doc_wm[] = "\n\t" "Enable debug messages for the window manager, shows all operators in search, shows " "keymap errors."; static const char arg_handle_debug_mode_generic_set_doc_ghost[] = "\n\t" "Enable debug messages for Ghost (Linux only)."; static const char arg_handle_debug_mode_generic_set_doc_wintab[] = "\n\t" "Enable debug messages for Wintab."; # ifdef WITH_XR_OPENXR static const char arg_handle_debug_mode_generic_set_doc_xr[] = "\n\t" "Enable debug messages for virtual reality contexts.\n" "\tEnables the OpenXR API validation layer, (OpenXR) debug messages and general information " "prints."; static const char arg_handle_debug_mode_generic_set_doc_xr_time[] = "\n\t" "Enable debug messages for virtual reality frame rendering times."; # endif static const char arg_handle_debug_mode_generic_set_doc_jobs[] = "\n\t" "Enable time profiling for background jobs."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] = "\n\t" "Enable all debug messages from dependency graph."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_build[] = "\n\t" "Enable debug messages from dependency graph related on graph construction."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_tag[] = "\n\t" "Enable debug messages from dependency graph related on tagging."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_time[] = "\n\t" "Enable debug messages from dependency graph related on timing."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_eval[] = "\n\t" "Enable debug messages from dependency graph related on evaluation."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] = "\n\t" "Switch dependency graph to a single threaded evaluation."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_pretty[] = "\n\t" "Enable colors for dependency graph debug messages."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_uuid[] = "\n\t" "Verify validness of session-wide identifiers assigned to ID datablocks."; static const char arg_handle_debug_mode_generic_set_doc_gpu_force_workarounds[] = "\n\t" "Enable workarounds for typical GPU issues and disable all GPU extensions."; static const char arg_handle_debug_mode_generic_set_doc_gpu_disable_ssbo[] = "\n\t" "Disable usage of shader storage buffer objects."; static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUSED(argv), void *data) { G.debug |= POINTER_AS_INT(data); return 0; } static const char arg_handle_debug_mode_io_doc[] = "\n\t" "Enable debug messages for I/O (Collada, ...)."; static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { G.debug |= G_DEBUG_IO; return 0; } static const char arg_handle_debug_mode_all_doc[] = "\n\t" "Enable all debug messages."; static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { G.debug |= G_DEBUG_ALL; # ifdef WITH_LIBMV libmv_startDebugLogging(); # endif # ifdef WITH_CYCLES_LOGGING CCL_start_debug_logging(); # endif return 0; } # ifdef WITH_LIBMV static const char arg_handle_debug_mode_libmv_doc[] = "\n\t" "Enable debug messages from libmv library."; static int arg_handle_debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { libmv_startDebugLogging(); return 0; } # endif # ifdef WITH_CYCLES_LOGGING static const char arg_handle_debug_mode_cycles_doc[] = "\n\t" "Enable debug messages from Cycles."; static int arg_handle_debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { CCL_start_debug_logging(); return 0; } # endif static const char arg_handle_debug_mode_memory_set_doc[] = "\n\t" "Enable fully guarded memory allocation and debugging."; static int arg_handle_debug_mode_memory_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { MEM_set_memory_debug(); return 0; } static const char arg_handle_debug_value_set_doc[] = "\n" "\tSet debug value of on startup."; static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--debug-value"; if (argc > 1) { const char *err_msg = NULL; int value; if (!parse_int(argv[1], NULL, &value, &err_msg)) { printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]); return 1; } G.debug_value = value; return 1; } printf("\nError: you must specify debug value to set.\n"); return 0; } static const char arg_handle_debug_gpu_set_doc[] = "\n" "\tEnable GPU debug context and information for OpenGL 4.3+."; static int arg_handle_debug_gpu_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { /* Also enable logging because that how gl errors are reported. */ const char *gpu_filter = "gpu.*"; CLG_type_filter_include(gpu_filter, strlen(gpu_filter)); G.debug |= G_DEBUG_GPU; return 0; } static const char arg_handle_gpu_backend_set_doc[] = "\n" "\tForce to use a specific GPU backend. Valid options: " # ifdef WITH_VULKAN_BACKEND "'vulkan', " # endif # ifdef WITH_METAL_BACKEND "'metal', " # endif "'opengl'."; static int arg_handle_gpu_backend_set(int argc, const char **argv, void *UNUSED(data)) { if (argc == 0) { printf("\nError: GPU backend must follow '--gpu-backend'.\n"); return 0; } eGPUBackendType gpu_backend = GPU_BACKEND_NONE; if (STREQ(argv[1], "opengl")) { gpu_backend = GPU_BACKEND_OPENGL; } # ifdef WITH_VULKAN_BACKEND else if (STREQ(argv[1], "vulkan")) { gpu_backend = GPU_BACKEND_VULKAN; } # endif # ifdef WITH_METAL_BACKEND else if (STREQ(argv[1], "metal")) { gpu_backend = GPU_BACKEND_METAL; } # endif else { printf("\nError: Unrecognized GPU backend for '--gpu-backend'.\n"); return 0; } GPU_backend_type_selection_set(gpu_backend); if (!GPU_backend_supported()) { printf("\nError: GPU backend not supported.\n"); return 0; } return 1; } static const char arg_handle_debug_fpe_set_doc[] = "\n\t" "Enable floating-point exceptions."; static int arg_handle_debug_fpe_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { main_signal_setup_fpe(); return 0; } static const char arg_handle_app_template_doc[] = "