当从handle_options符号时,decode_options相应地更新其他标识。flag_no_inline和flag_really_no_inline初始是2。如果合适,flag_no_inline将被common_handle_option 设为1(见该函数的1060行)。在下面,可以看到,如果内联是可能的,这2个变量均是0。而且如果optimize是0,flag_no_inline将是1,但flag_really_no_inline可能是0,以表示树内联器(tree inliner)关闭了内联;也可能是1,以表示内联由-fno-inline关闭。
decode_options (continue)
620 if (flag_pie)
621 flag_pic = flag_pie;
622 if (flag_pic && ! flag_pie)
623 flag_shlib = 1;
624
625 if (flag_no_inline == 2)
626 flag_no_inline = 0;
627 else
628 flag_really_no_inline = flag_no_inline;
629
630 /* Set flag_no_inline before the post_options () hook. The C front
631 ends use it to determine tree inlining defaults. FIXME: such
632 code should be lang-independent when all front ends use tree
633 inlining, in which case it, and this condition, should be moved
634 to the top of process_options() instead. */
635 if (optimize == 0)
636 {
637 /* Inlining does not work if not optimizing,
638 so force it not to be done. */
639 flag_no_inline = 1;
640 warn_inline = 0;
641
642 /* The c_decode_option function and decode_option hook set
643 this to `2' if -Wall is used, so we can avoid giving out
644 lots of errors for people who don't realize what -Wall does. */
645 if (warn_uninitialized == 1)
646 warning ("-Wuninitialized is not supported without -O");
647 }
648
649 if (flag_really_no_inline == 2)
650 flag_really_no_inline = flag_no_inline;
651 }
在decode_options完成编译选项处理后,回到toplev_main,接下来调用randomize初始化随机种子(random seeds)。进而,如果期望真正的编译,艰苦的工作由do_compile肇始。
4638 static void
4639 do_compile (void) in toplev.c
4640 {
4641 /* Initialize timing first. The C front ends read the main file in
4642 the post_options hook, and C++ does file timings. */
4643 if (time_report || !quiet_flag || flag_detailed_statistics)
4644 timevar_init ();
4645 timevar_start (TV_TOTAL);
4646
4647 process_options ();
虽然选项已由decode_options中的handle_options解析和记录,这里仍需要确认这些选项对于语言和目标平台是有效的。如果需要,还要进行调整。同时,还要根据这些选项设置编译器。
4271 static void
4272 process_options (void) in toplev.c
4273 {
4274 /* Just in case lang_hooks.post_options ends up calling a debug_hook.
4275 This can happen with incorrect pre-processed input. */
4276 debug_hooks = &do_nothing_debug_hooks;
4277
4278 /* Allow the front end to perform consistency checks and do further
4279 initialization based on the command line options. This hook also
4280 sets the original filename if appropriate (e.g. foo.i -> foo.c)
4281 so we can correctly initialize debug output. */
4282 no_backend = (*lang_hooks.post_options) (&main_input_filename);
上面,在4276行,debug_hooks及do_nothing_debug_hooks都是gcc_debug_hooks类型,该类型包含了调试信息输出函数的构子。起初,debug_hooks设为do_nothing_debug_hooks,它是不作任何事的钩子。
在4636行,lang_hooks的回调钩子post_options,对于C/C++,是c_common_post_options。
1060 bool
1061 c_common_post_options (const char **pfilename) in c-opts.c
1062 {
1063 struct cpp_callbacks *cb;
1064
1065 /* Canonicalize the input and output filenames. */
1066 if (in_fnames == NULL)
1067 {
1068 in_fnames = xmalloc (sizeof (in_fnames[0]));
1069 in_fnames[0] = "";
1070 }
1071 else if (strcmp (in_fnames[0], "-") == 0)
1072 in_fnames[0] = "";
1073
1074 if (out_fname == NULL || !strcmp (out_fname, "-"))
1075 out_fname = "";
1076
1077 if (cpp_opts->deps.style == DEPS_NONE)
1078 check_deps_environment_vars ();
1079
1080 handle_deferred_opts ();
1081
1082 sanitize_cpp_opts ();
1083
1084 register_include_chains (parse_in, sysroot, iprefix,
1085 std_inc, std_cxx_inc && c_dialect_cxx (), verbose);
C,C++的编译单元是一个源文件加上相关的头文件,这些文件名及路径由命令行选项传入。在handle_options,在453行,in_frames保存了这些文件名。
而在1074行,out_frame持有由-o选项指定的输出文件名。
如果没有使用-dN,-dM,-dD,-dI,就要检查环境变量DEPENDENCIES_OUTPUT或SUNPRO_DEPENDENCIES。
把DEPENDENCIES_OUTPUT设置为一文件名,会导致预处理器把基于依赖的(dependency-based)makefile规则至这个文件。但系统头文件名不包括在内。而对于SUNPRO_DEPENDENCIES,系统头文件亦被包括。如果这些环境变量被设为单个名字,它被认为是该输出文件名,而依赖规则的名字从源文件名获取。如果环境变量被设为2个名字,第二个名字即是依赖规则的目标名。设置这些环境变量的结果,等同于同时使用-MM,-MF和-MT。
1296 static void
1297 check_deps_environment_vars (void) in c-opts.c
1298 {
1299 char *spec;
1300
1301 GET_ENVIRONMENT (spec, "DEPENDENCIES_OUTPUT");
1302 if (spec)
1303 cpp_opts->deps.style = DEPS_USER;
1304 else
1305 {
1306 GET_ENVIRONMENT (spec, "SUNPRO_DEPENDENCIES");
1307 if (spec)
1308 {
1309 cpp_opts->deps.style = DEPS_SYSTEM;
1310 cpp_opts->deps.ignore_main_file = true;
1311 }
1312 }
1313
1314 if (spec)
1315 {
1316 /* Find the space before the DEPS_TARGET, if there is one. */
1317 char *s = strchr (spec, ' ');
1318 if (s)
1319 {
1320 /* Let the caller perform MAKE quoting. */
1321 defer_opt (OPT_MT, s + 1);
1322 *s = '/0';
1323 }
1324
1325 /* Command line -MF overrides environment variables and default. */
1326 if (!deps_file)
1327 deps_file = spec;
1328
1329 deps_append = 1;
1330 }
1331 }
前面,已经看到选项–MT或–MQ需要被延迟处理,而被缓存起来。在上面1080行,这些选项可以被处理了。
1334 static void
1335 handle_deferred_opts (void) in c-opts.c
1336 {
1337 size_t i;
1338
1339 for (i = 0; i < deferred_count; i++)
1340 {
1341 struct deferred_opt *opt = &deferred_opts[i];
1342
1343 if (opt->code == OPT_MT || opt->code == OPT_MQ)
1344 cpp_add_dependency_target (parse_in, opt->arg, opt->code == OPT_MQ);
1345 }
1346 }
因为–MT或-MQ改变了由依赖生成(dependency generation)所产生的目标文件名,这个目标名由cpp_add_dependency_target添加。
430 void
431 cpp_add_dependency_target (cpp_reader *pfile, const char *target, int quote) in cppinit.c
432 {
433 if (!pfile->deps)
434 pfile->deps = deps_init ();
435
436 deps_add_target (pfile->deps, target, quote);
437 }
在433行的deps被定义如下:
27 /* Keep this structure local to this file, so clients don't find it
28 easy to start making assumptions. */
29 struct deps
30 {
31 const char **targetv;
32 unsigned int ntargets; /* number of slots actually occupied */
33 unsigned int targets_size; /* amt of allocated space - in words */
34
35 const char **depv;
36 unsigned int ndeps;
37 unsigned int deps_size;
38 };
这个对象由deps_init初始化,而目标名由deps_add_target添加,其中参数quote表示是否需要引用(quote)名字中的特殊字符。
做完延迟选项处理后,sanitize_cpp_opts被调用,以执行一些合理性检查。
1350 static void
1351 sanitize_cpp_opts (void) in c-opts.c
1352 {
1353 /* If we don't know what style of dependencies to output, complain
1354 if any other dependency switches have been given. */
1355 if (deps_seen && cpp_opts->deps.style == DEPS_NONE)
1356 error ("to generate dependencies you must specify either -M or -MM");
1357
1358 /* -dM and dependencies suppress normal output; do it here so that
1359 the last -d[MDN] switch overrides earlier ones. */
1360 if (flag_dump_macros == 'M')
1361 flag_no_output = 1;
1362
1363 /* Disable -dD, -dN and -dI if normal output is suppressed. Allow
1364 -dM since at least glibc relies on -M -dM to work. */
1365 /* Also, flag_no_output implies flag_no_line_commands, always. */
1366 if (flag_no_output)
1367 {
1368 if (flag_dump_macros != 'M')
1369 flag_dump_macros = 0;
1370 flag_dump_includes = 0;
1371 flag_no_line_commands = 1;
1372 }
1373
1374 cpp_opts->unsigned_char = !flag_signed_char;
1375 cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS;
1376
1377 /* We want -Wno-long-long to override -pedantic -std=non-c99
1378 and/or -Wtraditional, whatever the ordering. */
1379 cpp_opts->warn_long_long
1380 = warn_long_long && ((!flag_isoc99 && pedantic) || warn_traditional);
1381
1382 /* If we're generating preprocessor output, emit current directory
1383 if explicitly requested or if debugging information is enabled.
1384 ??? Maybe we should only do it for debugging formats that
1385 actually output the current directory? */
1386 if (flag_working_directory == -1)
1387 flag_working_directory = (debug_info_level != DINFO_LEVEL_NONE);
1388 }
上面的1360行,flag_dump_macro在handle_OPT_d中设置,在为‘M’的情况下,仅宏被转储。而在1361行,flag_no_output如果非0,导致选项-E的输出不被完成,但诸如#define这样有副作用的指示仍被遵守。