2003-08-05 Alexandre Oliva * c.opt: Introduce -fworking-directory. * doc/cpp.texi, doc/invoke.texi, doc/cppopts.texi: Document it. * c-common.h (flag_working_directory): Declare. * c-common.c (flag_working_directory): Define. * c-opts.c (c_common_handle_options): Set it. (sanitize_cpp_opts): Set... * cpplib.h (struct cpp_options): ... working_directory option. (struct cpp_callbacks): Add dir_change. * cppinit.c (read_original_filename): Call... (read_original_directory): New. Look for # 1 "directory//" and process it. (cpp_read_main_file): Call dir_change callback if working_directory option is set. * gcc.c (cpp_unique_options): Pass -g*. * c-lex.c (cb_dir_change): New. (init_c_lex): Set dir_change callback. * toplev.c (src_pwd): New static variable. (set_src_pwd, get_src_pwd): New functions. * toplev.h (get_src_pwd, set_src_pwd): Declare. * dbxout.c (dbxout_init): Call get_src_pwd() instead of getpwd(). * dwarf2out.c (gen_compile_unit_die): Likewise. * dwarfout.c (output_compile_unit_die, dwarfout_init): Likewise. ================================================================================ --- gcc-3.3.4/gcc/c-common.c +++ gcc-3.3.4/gcc/c-common.c @@ -548,6 +548,13 @@ int flag_weak = 1; +/* 0 means we want the preprocessor to not emit line directives for + the current working directory. 1 means we want it to do it. -1 + means we should decide depending on whether debugging information + is being emitted or not. */ + +int flag_working_directory = -1; + /* Nonzero to use __cxa_atexit, rather than atexit, to register destructors for local statics and global objects. */ --- gcc-3.3.4/gcc/c-common.h +++ gcc-3.3.4/gcc/c-common.h @@ -711,6 +711,13 @@ extern int flag_weak; +/* 0 means we want the preprocessor to not emit line directives for + the current working directory. 1 means we want it to do it. -1 + means we should decide depending on whether debugging information + is being emitted or not. */ + +extern int flag_working_directory; + /* Nonzero to use __cxa_atexit, rather than atexit, to register destructors for local statics and global objects. */ --- gcc-3.3.4/gcc/c-lex.c +++ gcc-3.3.4/gcc/c-lex.c @@ -82,6 +82,7 @@ static void update_header_times PARAMS ((const char *)); static int dump_one_header PARAMS ((splay_tree_node, void *)); static void cb_line_change PARAMS ((cpp_reader *, const cpp_token *, int)); +static void cb_dir_change PARAMS ((cpp_reader *, const char *)); static void cb_ident PARAMS ((cpp_reader *, unsigned int, const cpp_string *)); static void cb_file_change PARAMS ((cpp_reader *, const struct line_map *)); @@ -119,6 +120,7 @@ cb = cpp_get_callbacks (parse_in); cb->line_change = cb_line_change; + cb->dir_change = cb_dir_change; cb->ident = cb_ident; cb->file_change = cb_file_change; cb->def_pragma = cb_def_pragma; @@ -206,6 +208,13 @@ return 0; } +static void +cb_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) +{ + if (! set_src_pwd (dir)) + warning ("too late for # directive to set debug directory"); +} + void dump_time_statistics () { --- gcc-3.3.4/gcc/c-opts.c +++ gcc-3.3.4/gcc/c-opts.c @@ -124,6 +124,7 @@ OPT("MQ", CL_ALL | CL_ARG, OPT_MQ) \ OPT("MT", CL_ALL | CL_ARG, OPT_MT) \ OPT("P", CL_ALL, OPT_P) \ + OPT("fworking-directory", CL_ALL, OPT_fworking_directory) \ OPT("Wabi", CL_CXX, OPT_Wabi) \ OPT("Wall", CL_ALL, OPT_Wall) \ OPT("Wbad-function-cast", CL_C, OPT_Wbad_function_cast) \ @@ -686,6 +687,10 @@ cpp_opts->no_line_commands = 1; break; + case OPT_fworking_directory: + flag_working_directory = on; + break; + case OPT_Wabi: warn_abi = on; break; @@ -1587,6 +1592,15 @@ and/or -Wtraditional, whatever the ordering. */ cpp_opts->warn_long_long = warn_long_long && ((!flag_isoc99 && pedantic) || warn_traditional); + + /* If we're generating preprocessor output, emit current directory + if explicitly requested or if debugging information is enabled. + ??? Maybe we should only do it for debugging formats that + actually output the current directory? */ + if (flag_working_directory == -1) + flag_working_directory = (debug_info_level != DINFO_LEVEL_NONE); + cpp_opts->working_directory + = flag_preprocess_only && flag_working_directory; } /* Set the C 89 standard (with 1994 amendments if C94, without GNU @@ -1790,6 +1804,10 @@ -dI Include #include directives in the output\n\ "), stdout); fputs (_("\ + -fworking-directory Generate a #line directive pointing at the\n\ + current working directory\n\ +"), stdout); + fputs (_("\ -f[no-]preprocessed Treat the input file as already preprocessed\n\ -ftabstop= Distance between tab stops for column reporting\n\ -P Do not generate #line directives\n\ --- gcc-3.3.4/gcc/cppinit.c +++ gcc-3.3.4/gcc/cppinit.c @@ -107,6 +107,7 @@ static void free_chain PARAMS ((struct pending_option *)); static void init_standard_includes PARAMS ((cpp_reader *)); static void read_original_filename PARAMS ((cpp_reader *)); +static void read_original_directory PARAMS ((cpp_reader *)); static void new_pending_directive PARAMS ((struct cpp_pending *, const char *, cl_directive_handler)); @@ -1026,6 +1027,24 @@ if (CPP_OPTION (pfile, preprocessed)) read_original_filename (pfile); + if (CPP_OPTION (pfile, working_directory)) + { + const char *name = pfile->map->to_file; + const char *dir = getpwd (); + char *dir_with_slashes = alloca (strlen (dir) + 3); + + memcpy (dir_with_slashes, dir, strlen (dir)); + memcpy (dir_with_slashes + strlen (dir), "//", 3); + + if (pfile->cb.dir_change) + pfile->cb.dir_change (pfile, dir); + /* Emit file renames that will be recognized by + read_directory_filename, since dir_change doesn't output + anything. */ + _cpp_do_file_change (pfile, LC_RENAME, dir_with_slashes, 1, 0); + _cpp_do_file_change (pfile, LC_RENAME, name, 1, 0); + } + return pfile->map->to_file; } @@ -1051,6 +1070,7 @@ if (token1->type == CPP_NUMBER) { _cpp_handle_directive (pfile, token->flags & PREV_WHITE); + read_original_directory (pfile); return; } } @@ -1059,6 +1079,61 @@ _cpp_backup_tokens (pfile, 1); } +/* For preprocessed files, if the tokens following the first filename + line is of the form # "/path/name//", handle the + directive so we know the original current directory. */ +static void +read_original_directory (pfile) + cpp_reader *pfile; +{ + const cpp_token *hash, *token; + + /* Lex ahead; if the first tokens are of the form # NUM, then + process the directive, otherwise back up. */ + hash = _cpp_lex_direct (pfile); + if (hash->type != CPP_HASH) + { + _cpp_backup_tokens (pfile, 1); + return; + } + + token = _cpp_lex_direct (pfile); + + if (token->type != CPP_NUMBER) + { + _cpp_backup_tokens (pfile, 2); + return; + } + + token = _cpp_lex_direct (pfile); + + if (token->type != CPP_STRING + || ! (token->val.str.len >= 5 + && token->val.str.text[token->val.str.len-2] == '/' + && token->val.str.text[token->val.str.len-3] == '/')) + { + _cpp_backup_tokens (pfile, 3); + return; + } + + if (pfile->cb.dir_change) + { + char *debugdir = alloca (token->val.str.len - 3); + + memcpy (debugdir, (const char *) token->val.str.text + 1, + token->val.str.len - 4); + debugdir[token->val.str.len - 4] = '\0'; + + pfile->cb.dir_change (pfile, debugdir); + } + + /* We want to process the fake line changes as regular changes, to + get them output. */ + _cpp_backup_tokens (pfile, 3); + + CPP_OPTION (pfile, working_directory) = false; +} + /* Handle pending command line options: -D, -U, -A, -imacros and -include. This should be called after debugging has been properly set up in the front ends. */ --- gcc-3.3.4/gcc/cpplib.h +++ gcc-3.3.4/gcc/cpplib.h @@ -407,6 +407,11 @@ /* Nonzero means __STDC__ should have the value 0 in system headers. */ unsigned char stdc_0_in_system_headers; + + /* Nonzero means output a directory line marker right after the + initial file name line marker, and before a duplicate initial + line marker. */ + bool working_directory; }; /* Call backs. */ @@ -415,6 +420,7 @@ /* Called when a new line of preprocessed output is started. */ void (*line_change) PARAMS ((cpp_reader *, const cpp_token *, int)); void (*file_change) PARAMS ((cpp_reader *, const struct line_map *)); + void (*dir_change) PARAMS ((cpp_reader *, const char *)); void (*include) PARAMS ((cpp_reader *, unsigned int, const unsigned char *, const cpp_token *)); void (*define) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *)); --- gcc-3.3.4/gcc/dbxout.c +++ gcc-3.3.4/gcc/dbxout.c @@ -438,7 +438,8 @@ if (use_gnu_debug_info_extensions) #endif { - if (!cwd && (cwd = getpwd ()) && (!*cwd || cwd[strlen (cwd) - 1] != '/')) + if (!cwd && (cwd = get_src_pwd ()) + && (!*cwd || cwd[strlen (cwd) - 1] != '/')) cwd = concat (cwd, FILE_NAME_JOINER, NULL); if (cwd) { --- gcc-3.3.4/gcc/doc/cpp.texi +++ gcc-3.3.4/gcc/doc/cpp.texi @@ -4066,7 +4066,9 @@ cpp [@option{-D}@var{macro}[=@var{defn}]@dots{}] [@option{-U}@var{macro}] [@option{-I}@var{dir}@dots{}] [@option{-W}@var{warn}@dots{}] [@option{-M}|@option{-MM}] [@option{-MG}] [@option{-MF} @var{filename}] - [@option{-MP}] [@option{-MQ} @var{target}@dots{}] [@option{-MT} @var{target}@dots{}] + [@option{-MP}] [@option{-MQ} @var{target}@dots{}] + [@option{-MT} @var{target}@dots{}] + [@option{-P}] [@option{-fno-working-directory}] [@option{-x} @var{language}] [@option{-std=}@var{standard}] @var{infile} @var{outfile} --- gcc-3.3.4/gcc/doc/cppopts.texi +++ gcc-3.3.4/gcc/doc/cppopts.texi @@ -1,4 +1,4 @@ -@c Copyright (c) 1999, 2000, 2001, 2002 +@c Copyright (c) 1999, 2000, 2001, 2002, 2003 @c Free Software Foundation, Inc. @c This is part of the CPP and GCC manuals. @c For copying conditions, see the file gcc.texi. @@ -470,6 +470,22 @@ line. If the value is less than 1 or greater than 100, the option is ignored. The default is 8. +@item -fworking-directory +@opindex fworking-directory +@opindex fno-working-directory +Enable generation of linemarkers in the preprocessor output that will +let the compiler know the current working directory at the time of +preprocessing. When this option is enabled, the preprocessor will +emit, after the initial linemarker, a second linemarker with the +current working directory followed by two slashes. GCC will use this +directory, when it's present in the preprocessed input, as the +directory emitted as the current working directory in some debugging +information formats. This option is implicitly enabled if debugging +information is enabled, but this can be inhibited with the negated +form @option{-fno-working-directory}. If the @option{-P} flag is +present in the command line, this option has no effect, since no +@code{#line} directives are emitted whatsoever. + @item -fno-show-column @opindex fno-show-column Do not print column numbers in diagnostics. This may be necessary if --- gcc-3.3.4/gcc/doc/invoke.texi +++ gcc-3.3.4/gcc/doc/invoke.texi @@ -294,7 +294,8 @@ -include @var{file} -imacros @var{file} @gol -iprefix @var{file} -iwithprefix @var{dir} @gol -iwithprefixbefore @var{dir} -isystem @var{dir} @gol --M -MM -MF -MG -MP -MQ -MT -nostdinc -P -remap @gol +-M -MM -MF -MG -MP -MQ -MT -nostdinc @gol +-P -fworking-directory -remap @gol -trigraphs -undef -U@var{macro} -Wp,@var{option}} @item Assembler Option --- gcc-3.3.4/gcc/dwarf2out.c +++ gcc-3.3.4/gcc/dwarf2out.c @@ -11764,7 +11764,7 @@ { dw_die_ref die; char producer[250]; - const char *wd = getpwd (); + const char *wd = get_src_pwd (); const char *language_string = lang_hooks.name; int language; @@ -13222,7 +13222,7 @@ if (get_AT (comp_unit_die, DW_AT_comp_dir) == NULL) { - char *wd = getpwd (); + char *wd = get_src_pwd (); unsigned i; if (wd != NULL) --- gcc-3.3.4/gcc/dwarfout.c +++ gcc-3.3.4/gcc/dwarfout.c @@ -4147,7 +4147,7 @@ stmt_list_attribute (LINE_BEGIN_LABEL); { - const char *wd = getpwd (); + const char *wd = get_src_pwd (); if (wd) comp_dir_attribute (wd); } @@ -6272,7 +6272,7 @@ ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SFNAMES_SECTION); ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL); { - const char *pwd = getpwd (); + const char *pwd = get_src_pwd (); char *dirname; if (!pwd) --- gcc-3.3.4/gcc/gcc.c +++ gcc-3.3.4/gcc/gcc.c @@ -725,7 +725,7 @@ in turn cause preprocessor symbols to be defined specially. */ static const char *cpp_options = "%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*}\ - %{O*} %{undef}"; + %{g*} %{O*} %{undef}"; /* This contains cpp options which are not passed when the preprocessor output will be used by another program. */ --- gcc-3.3.4/gcc/toplev.c +++ gcc-3.3.4/gcc/toplev.c @@ -1711,6 +1711,46 @@ FILE *rtl_dump_file = NULL; FILE *cgraph_dump_file = NULL; +/* The current working directory of a translation. It's generally the + directory from which compilation was initiated, but a preprocessed + file may specify the original directory in which it was + created. */ + +static const char *src_pwd; + +/* Initialize src_pwd with the given string, and return true. If it + was already initialized, return false. As a special case, it may + be called with a NULL argument to test whether src_pwd has NOT been + initialized yet. */ + +bool +set_src_pwd (const char *pwd) +{ + if (src_pwd) + { + if (strcmp (src_pwd, pwd) == 0) + return true; + else + return false; + } + + src_pwd = xstrdup (pwd); + return true; +} + +/* Return the directory from which the translation unit was initiated, + in case set_src_pwd() was not called before to assign it a + different value. */ + +const char * +get_src_pwd (void) +{ + if (! src_pwd) + src_pwd = getpwd (); + + return src_pwd; +} + /* Decode the string P as an integral parameter. If the string is indeed an integer return its numeric value else issue an Invalid Option error for the option PNAME and return DEFVAL. --- gcc-3.3.4/gcc/toplev.h +++ gcc-3.3.4/gcc/toplev.h @@ -133,4 +133,10 @@ extern int exact_log2_wide PARAMS ((unsigned HOST_WIDE_INT)); extern int floor_log2_wide PARAMS ((unsigned HOST_WIDE_INT)); +/* Functions used to get and set GCC's notion of in what directory + compilation was started. */ + +extern const char *get_src_pwd (void); +extern bool set_src_pwd (const char *); + #endif /* ! GCC_TOPLEV_H */