https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127895
Bug ID: 127895
Summary: MSP430: devices.csv lookup fails when GCC is invoked
via PATH
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: emendoz at clemson dot edu
Target Milestone: ---
There is a bug with the driver for the MSP430 target of gcc.
The docs (under section
-mmcu=name)[https://gcc.gnu.org/onlinedocs/gcc/MSP430-Options.html] state that
gcc will look for devices.csv in
<Toolchain-root>/msp430-elf{,bare}/include/devices
GCC can only find the devices.csv file if gcc was called using the full
executable path and not via the PATH env variable.
To reproduce this bug I configured/installed gcc 16.2.0 with the prefix set to
/opt/msp430-elf and added "/opt/msp430-elf/bin" to my PATH.
```
> which msp430-elf-gcc
/opt/msp430-elf/bin/msp430-elf-gcc
```
I created an empty file: /opt/msp430-elf/msp430-elf/include/devices/devices.csv
I created a header file: /opt/msp430-elf/msp430-elf/include/devices/sentinel.h
```
> cat /opt/msp430-elf/msp430-elf/include/devices/sentinel.h
// file:/opt/msp430-elf/msp430-elf/include/devices/sentinel.h
static const char * const sentinel = "This string is declared and defined in
sentinel.h";
```
in a temporary directory I have a test.c file
```
> cat test.c
#include <sentinel.h>
```
Then I called the compiler through PATH
```
> msp430-elf-gcc -v test.c -E -o test.i
Using built-in specs.
COLLECT_GCC=msp430-elf-gcc
Target: msp430-elf
Configured with:
/home/mephi/Documents/Work/persist/PersistResources/msp430/compile_msp430_gcc/gcc/configure
--target=msp430-elf --prefix=/opt/msp430-elf --enable-languages=c,c++
--disable-libssp --with-newlib --disable-hosted-libstdcxx
--with-gcc-major-version-only
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-E' '-o' 'test.i'
/opt/msp430-elf/libexec/gcc/msp430-elf/16/cc1 -E -quiet -v test.c -o test.i
-dumpbase test.c -dumpbase-ext .c
ignoring nonexistent directory
"/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/sys-include"
#include "..." search starts here:
#include <...> search starts here:
/opt/msp430-elf/lib/gcc/msp430-elf/16/include
/opt/msp430-elf/lib/gcc/msp430-elf/16/include-fixed
/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/include
End of search list.
test.c:1:10: fatal error: sentinel.h: No such file or directory
1 | #include <sentinel.h>
| ^~~~~~~~~~~~
compilation terminated.
```
Calling the compiler using the full compiler path works and produces the
expected behavior.
```
> /opt/msp430-elf/bin/msp430-elf-gcc -v test.c -E -o test.i
Using built-in specs.
COLLECT_GCC=/opt/msp430-elf/bin/msp430-elf-gcc
Target: msp430-elf
Configured with:
/home/mephi/Documents/Work/persist/PersistResources/msp430/compile_msp430_gcc/gcc/configure
--target=msp430-elf --prefix=/opt/msp430-elf --enable-languages=c,c++
--disable-libssp --with-newlib --disable-hosted-libstdcxx
--with-gcc-major-version-only
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-E' '-o' 'test.i'
/opt/msp430-elf/libexec/gcc/msp430-elf/16/cc1 -E -quiet -v test.c -o test.i
-dumpbase test.c -dumpbase-ext .c
ignoring nonexistent directory
"/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/sys-include"
#include "..." search starts here:
#include <...> search starts here:
/opt/msp430-elf/msp430-elf/include/devices
/opt/msp430-elf/lib/gcc/msp430-elf/16/include
/opt/msp430-elf/lib/gcc/msp430-elf/16/include-fixed
/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/include
End of search list.
COMPILER_PATH=/opt/msp430-elf/libexec/gcc/msp430-elf/16/:/opt/msp430-elf/libexec/gcc/msp430-elf/16/:/opt/msp430-elf/libexec/gcc/msp430-elf/:/opt/msp430-elf/lib/gcc/msp430-elf/16/:/opt/msp430-elf/lib/gcc/msp430-elf/:/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/bin/
LIBRARY_PATH=/opt/msp430-elf/lib/gcc/msp430-elf/16/:/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/lib/
COLLECT_GCC_OPTIONS='-v' '-E' '-o' 'test.i' '-dumpdir' 'test.'
> cat test.i
# 0 "test.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "test.c"
# 1 "/opt/msp430-elf/msp430-elf/include/devices/sentinel.h" 1 3
# 2 "/opt/msp430-elf/msp430-elf/include/devices/sentinel.h" 3
static const char * const sentinel = "This string is declared and defined in
sentinel.h";
# 2 "test.c" 2
```
I believe the code responsible for this bug is in
<git-root>/gcc/config/msp430/msp430-devices.cc:142
(msp430_check_env_var_for_devices)
This function checks MSP430_GCC_INCLUDE_DIR, GCC_EXEC_PREFIX, and COLLECT_GCC
environment variables. When MSP430_GCC_INCLUDE_DIR and GCC_EXEC_PREFIX are not
set msp430_check_env_var_for_devices will call
extract_devices_dir_from_collect_gcc.
msp430-devices.cc:120-131
```
/* Given the path to the GCC executable, return the path to the installed
device data in "$TOOLCHAIN_ROOT/msp430-elf/include/devices".
Assumes the GCC executable is in "$TOOLCHAIN_ROOT/<somedir>/". */
static void
extract_devices_dir_from_collect_gcc (char **devices_loc)
{
char *t_devices_loc = *devices_loc;
/* Go up a directory to the toolchain root. */
t_devices_loc = msp430_dirname (msp430_dirname (t_devices_loc));
t_devices_loc = concat (t_devices_loc, rest_of_devices_path, NULL);
*devices_loc = t_devices_loc;
}
```
The input to this function is the contents of the COLLECT_GCC environment
variable. When calling gcc using the full executable path the t_devices_loc has
these values:
initial: /opt/msp430-elf/bin/msp430-elf-gcc
after first msp430_dirname: /opt/msp430-elf/bin
after second msp430_dirname: /opt/msp430-elf
after concat: /opt/msp430-elf/msp430-elf/include/devices/
When calling gcc from the PATH however:
initial: msp430-elf-gcc
after first msp430_dirname: msp430-elf-gcc
after second msp430_dirname: msp430-elf-gcc
after concat: msp430-elf-gcc/msp430-elf/include/devices/
msp430_check_env_var_for_devices will then try to fopen
<t_devices_loc>/devices.csv which will either be
"/opt/msp430-elf/msp430-elf/include/devices/devices.csv" (correct path) or
"msp430-elf-gcc/msp430-elf/include/devices/devices.csv" (incorrect path)
depending on how gcc was called.
I confirmed this behavior by creating an empty devices.csv and a different
sentinel in <temporary-dir>/msp430-elf-gcc/msp430-elf/include/devices/
and called gcc:
```
> msp430-elf-gcc -v test.c -E -o test.i
Using built-in specs.
COLLECT_GCC=msp430-elf-gcc
Target: msp430-elf
Configured with:
/home/mephi/Documents/Work/persist/PersistResources/msp430/compile_msp430_gcc/gcc/configure
--target=msp430-elf --prefix=/opt/msp430-elf --enable-languages=c,c++
--disable-libssp --with-newlib --disable-hosted-libstdcxx
--with-gcc-major-version-only
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-E' '-o' 'test.i'
/opt/msp430-elf/libexec/gcc/msp430-elf/16/cc1 -E -quiet -v test.c -o test.i
-dumpbase test.c -dumpbase-ext .c
ignoring nonexistent directory
"/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/sys-include"
#include "..." search starts here:
#include <...> search starts here:
msp430-elf-gcc/msp430-elf/include/devices
/opt/msp430-elf/lib/gcc/msp430-elf/16/include
/opt/msp430-elf/lib/gcc/msp430-elf/16/include-fixed
/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/include
End of search list.
COMPILER_PATH=/opt/msp430-elf/libexec/gcc/msp430-elf/16/:/opt/msp430-elf/libexec/gcc/msp430-elf/16/:/opt/msp430-elf/libexec/gcc/msp430-elf/:/opt/msp430-elf/lib/gcc/msp430-elf/16/:/opt/msp430-elf/lib/gcc/msp430-elf/:/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/bin/
LIBRARY_PATH=/opt/msp430-elf/lib/gcc/msp430-elf/16/:/opt/msp430-elf/lib/gcc/msp430-elf/16/../../../../msp430-elf/lib/
COLLECT_GCC_OPTIONS='-v' '-E' '-o' 'test.i' '-dumpdir' 'test.'
> cat test.i
# 0 "test.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "test.c"
# 1 "msp430-elf-gcc/msp430-elf/include/devices/sentinel.h" 1 3
# 1 "msp430-elf-gcc/msp430-elf/include/devices/sentinel.h" 3
static const char * const sentinel_h = "This is the incorrect sentinel";
# 2 "test.c" 2
```