I found that the title might be misleading, so I’ll fix it in v2. The problem actually also occurs when the input is a preprocessed file (e.g. .i or .ii).
$ riscv64-unknown-elf-gcc x.i cc1: error: /home/scratch/build/install/riscv64-unknown-elf/usr/local/include: Permission denied cc1: error: /home/scratch/build/install/riscv64-unknown-elf/include: Permission denied On Tue, Nov 11, 2025 at 10:53 AM Kito Cheng <[email protected]> wrote: > > This fixes a permission error that occurs when cross-compiling with > -save-temps and a relocated toolchain, where the original build path > exists but is inaccessible. > > The issue only happened when: > - Building the toolchain at /home/scratch/build/ > - Installing it to another location like /home/user/rv64-toolchain/ > - The /home/scratch directory exists but has insufficient permissions > (e.g. drwx------ for `/home/scratch/`) > > Without this fix, cc1 would report errors like: > cc1: error: > /home/scratch/build/install/riscv64-unknown-elf/usr/local/include: Permission > denied > > This occurred because the GCC driver did not pass GCC_EXEC_PREFIX and > isysroot to cc1 in the compile stage when using -save-temps, causing > cc1 to search headers from the wrong (original build) path instead of > the relocated installation path. > > The fix ensures cc1 is aware of relocation by passing %I (which includes > isysroot) and setting the GCC_EXEC_PREFIX environment variable. > > Also another issue is cc1 will only silently ignore EPERM and ENOENT > (at remove_duplicates), but not EACCES, that make this issue more confusing, > maybe we could consider adding EACCES to the list of silently ignored errors > in > future, but I think this patch still worth since it will prevent us from > trying > wrong path at beginning, that could prevent unnessesary autofs mounting in > some > cases (Yeah, our server env will hit that). > > Or...another way we could try is we should not collect include path at > all when -fpreprocessed is specified, since the input is already > preprocessed. > > gcc/ChangeLog: > > * gcc.cc (default_compilers): Add %I to cc1 invocation for C and > C++ when using -save-temps. > (do_spec_1): Set GCC_EXEC_PREFIX environment variable before > collecting gcc options. > --- > gcc/gcc.cc | 12 +++++++----- > 1 file changed, 7 insertions(+), 5 deletions(-) > > diff --git a/gcc/gcc.cc b/gcc/gcc.cc > index eae7f07d962..e18415b5a47 100644 > --- a/gcc/gcc.cc > +++ b/gcc/gcc.cc > @@ -1469,10 +1469,10 @@ static const struct compiler default_compilers[] = > %eGNU C no longer supports -traditional without -E}\ > %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \ > %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\ > - cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \ > + cc1 %I -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \ > %(cc1_options)}\ > %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ > - cc1 %(cpp_unique_options) %(cc1_options)}}}\ > + cc1 %I %(cpp_unique_options) %(cc1_options)}}}\ > %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 1}, > {"-", > "%{!E:%e-E or -x required when input is from standard input}\ > @@ -1485,19 +1485,19 @@ static const struct compiler default_compilers[] = > %{!E:%{!M:%{!MM:\ > %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) > \ > %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\ > - cc1 -fpreprocessed %{save-temps*:%b.i} > %{!save-temps*:%g.i} \ > + cc1 %I -fpreprocessed %{save-temps*:%b.i} > %{!save-temps*:%g.i} \ > %(cc1_options)\ > %{!fsyntax-only:%{!S:-o %g.s} \ > %{!fdump-ada-spec*:%{!o*:--output-pch %w%i.gch}\ > %W{o*:--output-pch > %w%*}}%{!S:%V}}}\ > %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ > - cc1 %(cpp_unique_options) %(cc1_options)\ > + cc1 %I %(cpp_unique_options) %(cc1_options)\ > %{!fsyntax-only:%{!S:-o %g.s} \ > %{!fdump-ada-spec*:%{!o*:--output-pch %w%i.gch}\ > %W{o*:--output-pch > %w%*}}%{!S:%V}}}}}}}}", 0, 0, 0}, > {".i", "@cpp-output", 0, 0, 0}, > {"@cpp-output", > - "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) > %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0}, > + "%{!M:%{!MM:%{!E:cc1 %I -fpreprocessed %i %(cc1_options) > %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0}, > {".s", "@assembler", 0, 0, 0}, > {"@assembler", > "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 0, > 0}, > @@ -6146,6 +6146,8 @@ do_spec_1 (const char *spec, int inswitch, const char > *soft_matched_part) > argbuf.pop (); > } > > + if (gcc_exec_prefix) > + xputenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL)); > set_collect_gcc_options (); > > if (argbuf.length () > 0) > -- > 2.34.1 >
