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
>

Reply via email to