Avoid memory leaks on exit during argument parsing
[blender-staging.git] / source / creator / creator.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file creator/creator.c
29  *  \ingroup creator
30  */
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #ifdef WIN32
36 #  if defined(_MSC_VER) && defined(_M_X64)
37 #    include <math.h> /* needed for _set_FMA3_enable */
38 #  endif
39 #  include <windows.h>
40 #  include "utfconv.h"
41 #endif
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_args.h"
46 #include "BLI_threads.h"
47 #include "BLI_utildefines.h"
48 #include "BLI_callbacks.h"
49 #include "BLI_string.h"
50
51 /* mostly init functions */
52 #include "BKE_appdir.h"
53 #include "BKE_blender.h"
54 #include "BKE_brush.h"
55 #include "BKE_context.h"
56 #include "BKE_depsgraph.h" /* for DAG_init */
57 #include "BKE_font.h"
58 #include "BKE_global.h"
59 #include "BKE_material.h"
60 #include "BKE_modifier.h"
61 #include "BKE_node.h"
62 #include "BKE_sound.h"
63 #include "BKE_image.h"
64 #include "BKE_particle.h"
65
66
67 #include "IMB_imbuf.h"  /* for IMB_init */
68
69 #include "RE_engine.h"
70 #include "RE_render_ext.h"
71
72 #include "ED_datafiles.h"
73
74 #include "WM_api.h"
75
76 #include "RNA_define.h"
77
78 #ifdef WITH_FREESTYLE
79 #  include "FRS_freestyle.h"
80 #endif
81
82 /* for passing information between creator and gameengine */
83 #ifdef WITH_GAMEENGINE
84 #  include "BL_System.h"
85 #else /* dummy */
86 #  define SYS_SystemHandle int
87 #endif
88
89 #include <signal.h>
90
91 #ifdef __FreeBSD__
92 #  include <floatingpoint.h>
93 #endif
94
95 #ifdef WITH_BINRELOC
96 #  include "binreloc.h"
97 #endif
98
99 #ifdef WITH_LIBMV
100 #  include "libmv-capi.h"
101 #endif
102
103 #ifdef WITH_CYCLES_LOGGING
104 #  include "CCL_api.h"
105 #endif
106
107 #ifdef WITH_SDL_DYNLOAD
108 #  include "sdlew.h"
109 #endif
110
111 #include "creator_intern.h"  /* own include */
112
113
114 /*      Local Function prototypes */
115 #ifdef WITH_PYTHON_MODULE
116 int  main_python_enter(int argc, const char **argv);
117 void main_python_exit(void);
118 #endif
119
120 /* written to by 'creator_args.c' */
121 struct ApplicationState app_state = {
122         .signal = {
123                 .use_crash_handler = true,
124                 .use_abort_handler = true,
125         },
126         .exit_code_on_error = {
127                 .python = 0,
128         }
129 };
130
131 /* -------------------------------------------------------------------- */
132
133 /** \name Application Level Callbacks
134  *
135  * Initialize callbacks for the modules that need them.
136  *
137  * \{ */
138
139 static void callback_mem_error(const char *errorStr)
140 {
141         fputs(errorStr, stderr);
142         fflush(stderr);
143 }
144
145 static void main_callback_setup(void)
146 {
147         /* Error output from the alloc routines: */
148         MEM_set_error_callback(callback_mem_error);
149 }
150
151 /* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */
152 struct CreatorAtExitData {
153         bArgs *ba;
154 #ifdef WIN32
155         const char **argv;
156         int argv_num;
157 #endif
158 };
159
160 static void callback_main_atexit(void *user_data)
161 {
162         struct CreatorAtExitData *app_init_data = user_data;
163
164         if (app_init_data->ba) {
165                 BLI_argsFree(app_init_data->ba);
166                 app_init_data->ba = NULL;
167         }
168
169 #ifdef WIN32
170         if (app_init_data->argv) {
171                 while (app_init_data->argv_num) {
172                         free(app_init_data->argv[--app_init_data->argv_num]);
173                 }
174                 free(app_init_data->argv);
175                 app_init_data->argv = NULL;
176         }
177 #endif
178 }
179
180 /** \} */
181
182
183
184 /* -------------------------------------------------------------------- */
185
186 /** \name Main Function
187  * \{ */
188
189 #ifdef WITH_PYTHON_MODULE
190 /* allow python module to call main */
191 #  define main main_python_enter
192 static void *evil_C = NULL;
193
194 #  ifdef __APPLE__
195      /* environ is not available in mac shared libraries */
196 #    include <crt_externs.h>
197 char **environ = NULL;
198 #  endif
199 #endif
200
201 /**
202  * Blender's main function responsibilities are:
203  * - setup subsystems.
204  * - handle arguments.
205  * - run #WM_main() event loop,
206  *   or exit immediately when running in background mode.
207  */
208 int main(
209         int argc,
210 #ifdef WIN32
211         const char **UNUSED(argv_c)
212 #else
213         const char **argv
214 #endif
215         )
216 {
217         bContext *C;
218         SYS_SystemHandle syshandle;
219
220 #ifndef WITH_PYTHON_MODULE
221         bArgs *ba;
222 #endif
223
224 #ifdef WIN32
225         char **argv;
226         int argv_num;
227 #endif
228
229         /* --- end declarations --- */
230
231         /* ensure we free data on early-exit */
232         struct CreatorAtExitData app_init_data = {NULL};
233         BKE_blender_atexit_register(callback_main_atexit, &app_init_data);
234
235 #ifdef WIN32
236         /* We delay loading of openmp so we can set the policy here. */
237 # if defined(_MSC_VER)
238         _putenv_s("OMP_WAIT_POLICY", "PASSIVE");
239 # endif
240
241         /* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */
242 #  if defined(_MSC_VER) && defined(_M_X64)
243         _set_FMA3_enable(0);
244 #  endif
245
246         /* Win32 Unicode Args */
247         /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized
248          *       (it depends on the args passed in, which is what we're getting here!)
249          */
250         {
251                 wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
252                 argv = malloc(argc * sizeof(char *));
253                 for (argv_num = 0; argv_num < argc; argv_num++) {
254                         argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0);
255                 }
256                 LocalFree(argv_16);
257
258                 /* free on early-exit */
259                 app_init_data.argv = argv;
260                 app_init_data.argv_num = argv_num;
261         }
262 #endif  /* WIN32 */
263
264         /* NOTE: Special exception for guarded allocator type switch:
265          *       we need to perform switch from lock-free to fully
266          *       guarded allocator before any allocation happened.
267          */
268         {
269                 int i;
270                 for (i = 0; i < argc; i++) {
271                         if (STREQ(argv[i], "--debug") || STREQ(argv[i], "-d") ||
272                             STREQ(argv[i], "--debug-memory") || STREQ(argv[i], "--debug-all"))
273                         {
274                                 printf("Switching to fully guarded memory allocator.\n");
275                                 MEM_use_guarded_allocator();
276                                 break;
277                         }
278                         else if (STREQ(argv[i], "--")) {
279                                 break;
280                         }
281                 }
282         }
283
284 #ifdef BUILD_DATE
285         {
286                 time_t temp_time = build_commit_timestamp;
287                 struct tm *tm = gmtime(&temp_time);
288                 if (LIKELY(tm)) {
289                         strftime(build_commit_date, sizeof(build_commit_date), "%Y-%m-%d", tm);
290                         strftime(build_commit_time, sizeof(build_commit_time), "%H:%M", tm);
291                 }
292                 else {
293                         const char *unknown = "date-unknown";
294                         BLI_strncpy(build_commit_date, unknown, sizeof(build_commit_date));
295                         BLI_strncpy(build_commit_time, unknown, sizeof(build_commit_time));
296                 }
297         }
298 #endif
299
300 #ifdef WITH_SDL_DYNLOAD
301         sdlewInit();
302 #endif
303
304         C = CTX_create();
305
306 #ifdef WITH_PYTHON_MODULE
307 #ifdef __APPLE__
308         environ = *_NSGetEnviron();
309 #endif
310
311 #undef main
312         evil_C = C;
313 #endif
314
315
316
317 #ifdef WITH_BINRELOC
318         br_init(NULL);
319 #endif
320
321 #ifdef WITH_LIBMV
322         libmv_initLogging(argv[0]);
323 #elif defined(WITH_CYCLES_LOGGING)
324         CCL_init_logging(argv[0]);
325 #endif
326
327         main_callback_setup();
328         
329 #if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
330         /* patch to ignore argument finder gives us (pid?) */
331         if (argc == 2 && STREQLEN(argv[1], "-psn_", 5)) {
332                 extern int GHOST_HACK_getFirstFile(char buf[]);
333                 static char firstfilebuf[512];
334
335                 argc = 1;
336
337                 if (GHOST_HACK_getFirstFile(firstfilebuf)) {
338                         argc = 2;
339                         argv[1] = firstfilebuf;
340                 }
341         }
342 #endif
343         
344 #ifdef __FreeBSD__
345         fpsetmask(0);
346 #endif
347
348         /* initialize path to executable */
349         BKE_appdir_program_path_init(argv[0]);
350
351         BLI_threadapi_init();
352
353         BKE_blender_globals_init();  /* blender.c */
354
355         IMB_init();
356         BKE_images_init();
357         BKE_modifier_init();
358         DAG_init();
359
360         BKE_brush_system_init();
361         RE_texture_rng_init();
362         
363
364         BLI_callback_global_init();
365
366 #ifdef WITH_GAMEENGINE
367         syshandle = SYS_GetSystem();
368 #else
369         syshandle = 0;
370 #endif
371
372         /* first test for background */
373 #ifndef WITH_PYTHON_MODULE
374         ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */
375
376         /* ensure we free on early exit */
377         app_init_data.ba = ba;
378
379         main_args_setup(C, ba, &syshandle);
380
381         BLI_argsParse(ba, 1, NULL, NULL);
382
383         main_signal_setup();
384
385 #else
386         G.factory_startup = true;  /* using preferences or user startup makes no sense for py-as-module */
387         (void)syshandle;
388 #endif
389
390 #ifdef WITH_FFMPEG
391         IMB_ffmpeg_init();
392 #endif
393
394         /* after level 1 args, this is so playanim skips RNA init */
395         RNA_init();
396
397         RE_engines_init();
398         init_nodesystem();
399         psys_init_rng();
400         /* end second init */
401
402
403 #if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS)
404         G.background = true; /* python module mode ALWAYS runs in background mode (for now) */
405 #else
406         if (G.background) {
407                 main_signal_setup_background();
408         }
409 #endif
410
411         /* background render uses this font too */
412         BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
413
414         /* Initialize ffmpeg if built in, also needed for bg mode if videos are
415          * rendered via ffmpeg */
416         BKE_sound_init_once();
417         
418         init_def_material();
419
420         if (G.background == 0) {
421 #ifndef WITH_PYTHON_MODULE
422                 BLI_argsParse(ba, 2, NULL, NULL);
423                 BLI_argsParse(ba, 3, NULL, NULL);
424 #endif
425                 WM_init(C, argc, (const char **)argv);
426
427                 /* this is properly initialized with user defs, but this is default */
428                 /* call after loading the startup.blend so we can read U.tempdir */
429                 BKE_tempdir_init(U.tempdir);
430         }
431         else {
432 #ifndef WITH_PYTHON_MODULE
433                 BLI_argsParse(ba, 3, NULL, NULL);
434 #endif
435
436                 WM_init(C, argc, (const char **)argv);
437
438                 /* don't use user preferences temp dir */
439                 BKE_tempdir_init(NULL);
440         }
441 #ifdef WITH_PYTHON
442         /**
443          * NOTE: the U.pythondir string is NULL until WM_init() is executed,
444          * so we provide the BPY_ function below to append the user defined
445          * python-dir to Python's sys.path at this point.  Simply putting
446          * WM_init() before #BPY_python_start() crashes Blender at startup.
447          */
448
449         /* TODO - U.pythondir */
450 #else
451         printf("\n* WARNING * - Blender compiled without Python!\nthis is not intended for typical usage\n\n");
452 #endif
453         
454         CTX_py_init_set(C, 1);
455         WM_keymap_init(C);
456
457 #ifdef WITH_FREESTYLE
458         /* initialize Freestyle */
459         FRS_initialize();
460         FRS_set_context(C);
461 #endif
462
463         /* OK we are ready for it */
464 #ifndef WITH_PYTHON_MODULE
465         main_args_setup_post(C, ba);
466         
467         if (G.background == 0) {
468                 if (!G.file_loaded)
469                         if (U.uiflag2 & USER_KEEP_SESSION)
470                                 WM_recover_last_session(C, NULL);
471         }
472
473 #endif
474
475         /* Explicitly free data allocated for argument parsing:
476          * - 'ba'
477          * - 'argv' on WIN32.
478          */
479         callback_main_atexit(&app_init_data);
480         BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data);
481
482         /* paranoid, avoid accidental re-use */
483 #ifndef WITH_PYTHON_MODULE
484         ba = NULL;
485         (void)ba;
486 #endif
487
488 #ifdef WIN32
489         argv = NULL;
490         (void)argv;
491 #endif
492
493 #ifdef WITH_PYTHON_MODULE
494         return 0; /* keep blender in background mode running */
495 #endif
496
497         if (G.background) {
498                 /* Using window-manager API in background mode is a bit odd, but works fine. */
499                 WM_exit(C);
500         }
501         else {
502                 if (G.fileflags & G_FILE_AUTOPLAY) {
503                         if (G.f & G_SCRIPT_AUTOEXEC) {
504                                 if (WM_init_game(C)) {
505                                         return 0;
506                                 }
507                         }
508                         else {
509                                 if (!(G.f & G_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
510                                         G.f |= G_SCRIPT_AUTOEXEC_FAIL;
511                                         BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Game AutoStart");
512                                 }
513                         }
514                 }
515
516                 if (!G.file_loaded) {
517                         WM_init_splash(C);
518                 }
519         }
520
521         WM_main(C);
522
523         return 0;
524 } /* end of int main(argc, argv)        */
525
526 #ifdef WITH_PYTHON_MODULE
527 void main_python_exit(void)
528 {
529         WM_exit_ext((bContext *)evil_C, true);
530         evil_C = NULL;
531 }
532 #endif
533
534 /** \} */