I am unable to figure this out. I am trying to build the Microchip XC32 PIC32 microcontroller GCC cross-compiler.
To try it yourself (this is how I got to my error I'm stuck on):
On Windows 10 or Windows 11: enable "developer mode" to allow symlinks. Windows key --> search for "Use developer features", click the button (now blue in the image below) to turn it on:
Clone my repo here: https://github.com/ElectricRCAircraftGuy/Microchip_XC32_Compiler
Install MSYS2, and open the MSYS2 UCRT64 shell. Optionally, follow my full MSYS2 setup instructions here.
Install dependencies via pacman, like this: copy and paste this whole blob all at once, into the terminal:
# ============= DO THIS TO INSTALL ALL DEPENDENCIES AT ONCE! =============
# UCRT64
if [ "$MSYSTEM" != "UCRT64" ]; then
echo "ERROR: You must run this script in an MSYS2 ucrt64 terminal!"
exit 1
fi
package_list=(
"mingw-w64-ucrt-x86_64-gcc" # specific version for MSYS2 ucrt64
"make"
"binutils"
"autoconf"
"autogen"
"bison"
"dejagnu"
"flex"
"gawk"
"gperf"
"gzip"
# "nsis" # generic; must be specific; hence the line below
"mingw-w64-ucrt-x86_64-nsis" # specific version for MSYS2 ucrt64
"perl"
"scons"
"tcl"
"texinfo"
"wget"
"zip"
# "texlive" # generic; must be specific; hence the line below
"mingw-w64-ucrt-x86_64-texlive-core" # specific version for MSYS2 ucrt64
# "texlive-extra-utils" # generic; must be specific; hence the line below
"mingw-w64-ucrt-x86_64-texlive-extra-utils" # specific version for MSYS2 ucrt64
)
# Only install packages if tHey are NOT already installed.
for package in "${package_list[@]}"; do
if ! pacman -Qs $package > /dev/null; then
echo -e "\n=== $package is not installed. Installing... ==="
pacman -S --noconfirm $package
else
echo -e "\n=== $package is already installed. ==="
fi
done
echo -e "\n=== Done installing packages! ===\n"
Run the build script: build-xc32-v4.35m.sh
:
time ./build-xc32-v4.35m.sh
About 20 minutes into it, it fails when compiling gcc, while configuring GMP. Note that to get clean errors you must modify the build script to use -j1
instead of -j$(nproc)
, here in the first line, or else you'll get multi-threaded output garbled on top of each other in the terminal:
time make -j$(nproc) all-gcc \
STAGE1_LIBS="-lexpat -lmchp -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic" \
CPPFLAGS="-I${hostinstalldir}/include -imacros host-defs.h" \
LDFLAGS=-L${hostinstalldir}/lib
make install-gcc
Here's my failure. Configuring GMP seems to fail when it's looking for mp_limb_t
. I've marked some notes/lines with <====
below:
checking for sysctl... no
checking for sysctlbyname... no
checking for times... no
checking for library containing clock_gettime... none required
checking for vsnprintf... yes
checking whether vsnprintf works... probably
configure: WARNING: cannot check for properly working vsnprintf when cross compiling, will assume it's ok
checking whether sscanf needs writable input... no
checking for struct pst_processor.psp_iticksperclktick... no
checking size of void *... 8
checking size of unsigned short... 2
checking size of unsigned... 4
checking size of unsigned long... 4
checking size of mp_limb_t... 0 <===== SIZE SHOULD BE 8
configure: error: Oops, mp_limb_t doesn't seem to work <===== ERROR
make: *** [Makefile:4701: configure-gmp] Error 1
real 3m27.324s
user 0m1.373s
sys 0m30.921s
Error: [gcc] failed to build!
real 3m27.510s
user 0m1.373s
Note that the build script runs perfectly to completion on Ubuntu 22.04, once I install the dependencies. It's Windows in MSYS2 that I am unable to get it to work in. Any help is greatly appreciated. This will help the PIC32 community build with GCC without having to buy a license from Microchip. The cross-compiler is GPL-licensed.
I've left a comment here too with a little more detail: https://github.com/JuliaLang/julia/issues/13206#issuecomment-1791823912. I no longer think symlinks are the issue, as I've tried copying the data directly over them with no change.
I have provided the autogenerated Makefile
and gcc/gmp/config.log
files here: https://github.com/ElectricRCAircraftGuy/Microchip_XC32_Compiler/tree/main/temp_debug_files. I've described them in the README.md file in that directory.
Been stuck on this for days. Could use some community support.
If anyone wants to try it in the MSYS2 MINGW64 environment instead, here is how to install those dependencies in that terminal:
# ============= DO THIS TO INSTALL ALL DEPENDENCIES AT ONCE! =============
# mingw64
if [ "$MSYSTEM" != "MINGW64" ]; then
echo "ERROR: You must run this script in an MSYS2 mingw64 terminal!"
exit 1
fi
package_list=(
"mingw-w64-x86_64-gcc" # specific version for MSYS2 mingw64
"make"
"binutils"
"autoconf"
"autogen"
"bison"
"dejagnu"
"flex"
"gawk"
"gperf"
"gzip"
# "nsis" # generic; must be specific; hence the line below
"mingw-w64-x86_64-nsis" # specific version for MSYS2 mingw64
"perl"
"scons"
"tcl"
"texinfo"
"wget"
"zip"
# "texlive" # generic; must be specific; hence the line below
"mingw-w64-x86_64-texlive-core" # specific version for MSYS2 mingw64
# "texlive-extra-utils" # generic; must be specific; hence the line below
"mingw-w64-x86_64-texlive-extra-utils" # specific version for MSYS2 mingw64
)
# Only install packages if tHey are NOT already installed.
for package in "${package_list[@]}"; do
if ! pacman -Qs $package > /dev/null; then
echo -e "\n=== $package is not installed. Installing... ==="
pacman -S --noconfirm $package
else
echo -e "\n=== $package is already installed. ==="
fi
done
echo -e "\n=== Done installing packages! ===\n"
Here's the autogenerated Makefile chunk of interest: C:\Users\gabriel\GS\dev\Microchip_XC32_Compiler\xc32-v4.35-src\pic32m-build\gcc\Makefile
:
.PHONY: configure-gmp maybe-configure-gmp
maybe-configure-gmp:
maybe-configure-gmp: configure-gmp
configure-gmp:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
test ! -f $(HOST_SUBDIR)/gmp/Makefile || exit 0; \
$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/gmp; \
$(HOST_EXPORTS) \
echo Configuring in $(HOST_SUBDIR)/gmp; \
cd "$(HOST_SUBDIR)/gmp" || exit 1; \
case $(srcdir) in \
/* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
*) topdir=`echo $(HOST_SUBDIR)/gmp/ | \
sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
esac; \
module_srcdir=gmp; \
$(SHELL) \
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=none-${host_vendor}-${host_os} \
--target=none-${host_vendor}-${host_os} --disable-shared LEX="touch lex.yy.c" \
|| exit 1
Note to self: I think a leading /
in an include may be interpreted by MSYS GCC as C:\
, which means that /c/my/path
is seen as C:\c\my\path
instead of as C:\my\path
. This is contrary to how the MSYS terminal handles it, however. What a PITA. Study the sources above.
Convert to relative paths in the build script, using realpath --relative-to
. Update my Stack Overflow answer on this too: https://stackoverflow.com/a/60157372/4561887
Solved. Big thanks to @HolyBlackCat for the comments and help, including this one, which got me started on finding the solution.
#include
paths are not allowed in C and C++!It turns out it's an MSYS2 gcc absolute path issue/bug. You cannot call the configure
script with an absolute path since it uses the call path to generate a C include in the build process. And, absolute paths are broken in C or C++ includes in MSYS2 on Windows.
So, change this part in build-xc32-v4.35m.sh
:
# Finally, GCC.
PS4="[gcc] "
(
set -ex
rm -rf ${gcc_builddir}
mkdir -p ${gcc_builddir}
cd ${gcc_builddir}
${gcc_srcdir}/configure \
# ...
To this. The only change is the creation and usage of gcc_srcdir_RELATIVE
to call the configure
script with a relative path instead of an absolute path!:
# Finally, GCC.
PS4="[gcc] "
(
set -ex
rm -rf ${gcc_builddir}
mkdir -p ${gcc_builddir}
cd ${gcc_builddir}
# Obtain relative paths, since Windows doesn't like absolute paths due to Windows/Linux path
# differences in gcc includes.
gcc_srcdir_RELATIVE=$(realpath --relative-to="." "${gcc_srcdir}")
${gcc_srcdir_RELATIVE}/configure \
# ...
If you obtain these relative paths:
INSTALLDIR_RELATIVE=$(realpath --relative-to="." "${INSTALLDIR}")
hostinstalldir_RELATIVE=$(realpath --relative-to="." "${hostinstalldir}")
...and use them inside the build script like this:
INSTALLDIR_RELATIVE=$(realpath --relative-to="." "${INSTALLDIR}")
hostinstalldir_RELATIVE=$(realpath --relative-to="." "${hostinstalldir}")
${gcc_srcdir}/configure \
--target=pic32mx \
--prefix=${INSTALLDIR_RELATIVE} \
--program-prefix=pic32m- \
--with-sysroot=${INSTALLDIR_RELATIVE}/pic32mx \
--with-bugurl=http://example.com \
--with-pkgversion="Microchip XC32 Compiler v4.35 custom" \
--bindir=${INSTALLDIR_RELATIVE}/bin/bin \
--infodir=${INSTALLDIR_RELATIVE}/share/doc/xc32-pic32m-gcc/info \
--mandir=${INSTALLDIR_RELATIVE}/share/doc/xc32-pic32m-gcc/man \
--libdir=${INSTALLDIR_RELATIVE}/lib \
--libexecdir=${INSTALLDIR_RELATIVE}/bin/bin \
--with-build-sysroot=${INSTALLDIR_RELATIVE}/pic32mx \
--enable-stage1-languages=c \
--enable-languages=c,c++ \
--enable-target-optspace \
--disable-comdat \
--disable-libstdcxx-pch \
--disable-libstdcxx-verbose \
--disable-libssp \
--disable-libmudflap \
--disable-libffi \
--disable-libfortran \
--disable-bootstrap \
--disable-shared \
--disable-nls \
--disable-gdb \
--disable-libgomp \
--disable-threads \
--disable-tls \
--disable-sim \
--disable-decimal-float \
--disable-libquadmath \
--disable-shared \
--disable-checking \
--disable-maintainer-mode \
--enable-lto \
--enable-fixed-point \
--enable-gofast \
--enable-static \
--enable-sgxx-sde-multilibs \
--enable-sjlj-exceptions \
--enable-poison-system-directories \
--enable-obsolete \
--without-isl \
--without-cloog \
--without-headers \
--with-musl \
--with-dwarf2 \
--with-gnu-as \
--with-gnu-ld \
'--with-host-libstdcxx=-static-libgcc -static-libstdc++ -Wl,-lstdc++ -lm' \
CPPFLAGS="-I${hostinstalldir_RELATIVE}/include -imacros host-defs.h" \
LDFLAGS=-L${hostinstalldir_RELATIVE}/lib
time make -j$(nproc) all-gcc \
STAGE1_LIBS="-lexpat -lmchp -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic" \
CPPFLAGS="-I${hostinstalldir_RELATIVE}/include -imacros host-defs.h" \
LDFLAGS=-L${hostinstalldir_RELATIVE}/lib
...that just breaks the build. It doesn't work. The build system complains that all (or almost all) of those paths need to be absolute paths. The only fix you need is therefore the relative call to the configure
script, like this: ${gcc_srcdir_RELATIVE}/configure
.
${gcc_srcdir_RELATIVE}/configure
relative path fix that worksCalling the gcc configure
script with a relative path causes that relative path to get inserted into the main gcc Makefile
, and then passed to the gmp configure
script, where it is injected into an autogenerated conftest.c
C file as an include statement. So, using an absolute path to call the gcc configure
script puts an absolute path in the #include
inside conftest.c
, and using a relative path to call the gcc configure
script puts a relative path into that #include
statement. In the MSYS2 UCRT64 gcc compiler, however, only relative paths are allowed, due to path conversion issues of the C:\
(in a Windows-style path) or /c/
(in a Unix-style path on Windows) part which pertains to the beginning of absolute paths.
By doing this, the srcdir
variable in the top of the Microchip_XC32_Compiler/xc32-v4.35-src/pic32m-build/gcc/Makefile
file changes from this absolute path here:
srcdir = /c/Users/gbriel/GS/dev/Microchip_XC32_Compiler/xc32-v4.35-src/pic32m-source/gcc
To this relative path here:
srcdir = ../../pic32m-source/gcc
The following is in the same Makefile here. Notice that topdir=$(srcdir)
, and --srcdir=$${topdir}/$$module_srcdir
is passed to the call to configure
for the gmp
library.
.PHONY: configure-gmp maybe-configure-gmp
maybe-configure-gmp:
maybe-configure-gmp: configure-gmp
configure-gmp:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
test ! -f $(HOST_SUBDIR)/gmp/Makefile || exit 0; \
$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/gmp; \
$(HOST_EXPORTS) \
echo Configuring in $(HOST_SUBDIR)/gmp; \
cd "$(HOST_SUBDIR)/gmp" || exit 1; \
case $(srcdir) in \
/* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
*) topdir=`echo $(HOST_SUBDIR)/gmp/ | \
sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
esac; \
module_srcdir=gmp; \
$(SHELL) \
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=none-${host_vendor}-${host_os} \
--target=none-${host_vendor}-${host_os} --disable-shared LEX="touch lex.yy.c" \
|| exit 1
Well, the gmp configure
script uses that --srcdir
parameter to set this include, as shown in Microchip_XC32_Compiler/xc32-v4.35-src/pic32m-build/gcc/gmp/config.log
here:
configure:27432: gcc -c -g -O2 -D__USE_MINGW_ACCESS -DNO_ASM -I/c/Users/gabriel/GS/dev/Microchip_XC32_Compiler/xc32-v4.35-src/pic32m-build/opt/include -imacros host-defs.h conftest.c >&5
conftest.c:80:10: fatal error: /c/Users/gabriel/GS/dev/Microchip_XC32_Compiler/xc32-v4.35-src/pic32m-source/gcc/gmp/gmp-h.in: No such file or directory
80 | #include "/c/Users/gabriel/GS/dev/Microchip_XC32_Compiler/xc32-v4.35-src/pic32m-source/gcc/gmp/gmp-h.in"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
And, due to this not-a-bug bug, absolute Linux-style includes in MSYS2 gcc on Windows are not allowed:
Strange thing is that passing absolute path as command line argument to
g++
works, but using it as include does not.e.g.
g++ -c /c/Users/travis/build/config.cpp
works, i.e. it finds the
cpp
file, and translates the/c/...
path toC:/...
path but giving that include error:C:/Users/travis/build/config.cpp:1:10: fatal error: /c/Users/travis/build/config.hpp: No such file or directory 1 | #include "/c/Users/travis/build/config.hpp" | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, by calling ${gcc_srcdir_RELATIVE}/configure
, that include now looks like this in the autogenerated conftest.c
file, and it works just fine!:
#include "../../../pic32m-source/gcc/gmp/gmp-h.in"
Note that in the process of figuring this out, I tried testing Windows-style include paths like this:
#include "C:\Users\gabriel\GS\dev\Microchip_XC32_Compiler\xc32-v4.35-src\pic32m-source\gcc\gmp\gmp-h.in"
...and I'm pretty sure those failed in gcc running in MSYS2 UCRT64 too.
I consider this absolute path problem in gcc in MSYS2 a definite bug. Update: it's not a bug. It was my user error and misunderstanding.
And now I'm on to my next bug in this very difficult build process. :/
From the bottom of my question:
--build=
, --host=
, and --target=
arguments to configure
scripts.~
directory in a Windows install of Git Bash - see in particular the section titled, "More details on paths in Git Bash and MSYS2"