Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -3134,6 +3134,45 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
return -1;
}

#ifdef ENSURE_MSYSTEM_IS_SET
#if !defined(RUNTIME_PREFIX) || !defined(HAVE_WPGMPTR) || !defined(MINGW_PREFIX)
static size_t append_system_bin_dirs(char *path UNUSED, size_t size UNUSED)
{
return 0;
}
#else
static size_t append_system_bin_dirs(char *path, size_t size)
{
char prefix[32768];
const char *slash;
size_t len = xwcstoutf(prefix, _wpgmptr, sizeof(prefix)), off = 0;

if (len == 0 || len >= sizeof(prefix) ||
!(slash = find_last_dir_sep(prefix)))
return 0;
/* strip trailing `git.exe` */
len = slash - prefix;

/* strip trailing `cmd` or `<mingw-prefix>\bin` or `bin` or `libexec\git-core` */
if (strip_suffix_mem(prefix, &len, "\\" MINGW_PREFIX "\\libexec\\git-core") ||
strip_suffix_mem(prefix, &len, "\\" MINGW_PREFIX "\\bin"))
off += xsnprintf(path + off, size - off,
"%.*s\\" MINGW_PREFIX "\\bin;", (int)len, prefix);
else if (strip_suffix_mem(prefix, &len, "\\cmd") ||
strip_suffix_mem(prefix, &len, "\\bin") ||
strip_suffix_mem(prefix, &len, "\\libexec\\git-core"))
off += xsnprintf(path + off, size - off,
"%.*s\\" MINGW_PREFIX "\\bin;", (int)len, prefix);
else
return 0;

off += xsnprintf(path + off, size - off,
"%.*s\\usr\\bin;", (int)len, prefix);
return off;
}
#endif
#endif

static void setup_windows_environment(void)
{
char *tmp = getenv("TMPDIR");
Expand Down Expand Up @@ -3185,6 +3224,35 @@ static void setup_windows_environment(void)
if (!tmp && (tmp = getenv("USERPROFILE")))
setenv("HOME", tmp, 1);
}

if (!getenv("PLINK_PROTOCOL"))
setenv("PLINK_PROTOCOL", "ssh", 0);

#ifdef ENSURE_MSYSTEM_IS_SET
if (!(tmp = getenv("MSYSTEM")) || !tmp[0]) {
const char *home = getenv("HOME"), *path = getenv("PATH");
char buf[32768];
size_t off = 0;

setenv("MSYSTEM", ENSURE_MSYSTEM_IS_SET, 1);

if (home)
off += xsnprintf(buf + off, sizeof(buf) - off,
"%s\\bin;", home);
off += append_system_bin_dirs(buf + off, sizeof(buf) - off);
if (path)
off += xsnprintf(buf + off, sizeof(buf) - off,
"%s", path);
else if (off > 0)
buf[off - 1] = '\0';
else
buf[0] = '\0';
setenv("PATH", buf, 1);
}
#endif

if (!getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"))
setenv("LC_CTYPE", "C.UTF-8", 1);
}

int mingw_platform_has_symlinks(void)
Expand Down
61 changes: 27 additions & 34 deletions config.mak.uname
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,8 @@ ifeq ($(uname_S),Windows)
GIT_VERSION := $(GIT_VERSION).MSVC

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> -                ifeq (CLANGARM64,$(MSYSTEM))
> -			prefix = /clangarm64
> -                else
> -			prefix = /mingw64
> -                endif
> +        ifneq (,$(MSYSTEM))
> +		prefix = $(MINGW_PREFIX)
>          endif

Mental note: if $(MSYSTEM) is not an empty string, we set prefix to
$(MINGW_PREFIX).

> @@ -755,6 +749,10 @@ ifeq ($(uname_S),MINGW)
>  		BASIC_LDFLAGS += -Wl,--dynamicbase
>          endif
>          ifneq (,$(MSYSTEM))
> +                ifeq ($(MINGW_PREFIX),$(filter-out /%,$(MINGW_PREFIX)))
> +			# Override if empty or does not start with a slash
> +			MINGW_PREFIX := /$(shell echo '$(MSYSTEM)' | tr A-Z a-z)
> +                endif

Mental note: MINGW_PREFIX that does not begin with a slash is forced
to begin with a slash.

>  		prefix = $(MINGW_PREFIX)

And that becomes $(prefix).

> diff --git a/meson.build b/meson.build
> index 7073d5844d..6ddc461873 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1318,7 +1318,6 @@ elif host_machine.system() == 'windows'
>  
>    libgit_c_args += [
>      '-DDETECT_MSYS_TTY',
> -    '-DENSURE_MSYSTEM_IS_SET',
>      '-DNATIVE_CRLF',
>      '-DNOGDI',
>      '-DNO_POSIX_GOODIES',
> @@ -1328,6 +1327,18 @@ elif host_machine.system() == 'windows'
>      '-D__USE_MINGW_ANSI_STDIO=0',
>    ]
>  
> +  msystem = get_option('msystem')
> +  if msystem != ''
> +    mingw_prefix = get_option('mingw_prefix')
> +    if mingw_prefix == ''
> +      mingw_prefix = '/' + msystem.to_lower()
> +    endif
> +    libgit_c_args += [
> +      '-DENSURE_MSYSTEM_IS_SET="' + msystem + '"',
> +      '-DMINGW_PREFIX="' + mingw_prefix + '"'
> +    ]
> +  endif

Lowercase mingw_prefix in Meson world corresponds to MINGW_PREFIX in
Make world, I guess.  -DMINGW_PRFIX gets mingw_prefix which begins
with a slash.

I do not do Windows or Meson, but doesn't this contradict with what
we have in [12/12], part of which says:

diff --git a/config.mak.uname b/config.mak.uname
index 2f7d445eb3..0b63be10b7 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -535,7 +535,9 @@ endif
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/trace2_win32_process_info.o \
 		compat/win32/dirent.o
-	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
+	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY \
+		-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" -DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\"" \
+		-DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
 	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
 	# invalidcontinue.obj allows Git's source code to close the same file
 	# handle twice, or to access the osfhandle of an already-closed stdout


IOW, -DMINGW_PREFIX passed to the compiler strips leading slash from
$(MINGW_PREFIX).

Isn't it necessary to strip the leading slash from ming_prefix also
on the Meson side?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Johannes Schindelin wrote on the Git mailing list (how to reply to this email):

Hi Junio,

On Wed, 5 Aug 2026, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
> [...]
> > diff --git a/meson.build b/meson.build
> > index 7073d5844d..6ddc461873 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -1318,7 +1318,6 @@ elif host_machine.system() == 'windows'
> >  
> >    libgit_c_args += [
> >      '-DDETECT_MSYS_TTY',
> > -    '-DENSURE_MSYSTEM_IS_SET',
> >      '-DNATIVE_CRLF',
> >      '-DNOGDI',
> >      '-DNO_POSIX_GOODIES',
> > @@ -1328,6 +1327,18 @@ elif host_machine.system() == 'windows'
> >      '-D__USE_MINGW_ANSI_STDIO=0',
> >    ]
> >  
> > +  msystem = get_option('msystem')
> > +  if msystem != ''
> > +    mingw_prefix = get_option('mingw_prefix')
> > +    if mingw_prefix == ''
> > +      mingw_prefix = '/' + msystem.to_lower()
> > +    endif
> > +    libgit_c_args += [
> > +      '-DENSURE_MSYSTEM_IS_SET="' + msystem + '"',
> > +      '-DMINGW_PREFIX="' + mingw_prefix + '"'
> > +    ]
> > +  endif
> 
> Lowercase mingw_prefix in Meson world corresponds to MINGW_PREFIX in
> Make world, I guess.  -DMINGW_PRFIX gets mingw_prefix which begins
> with a slash.
> 
> I do not do Windows or Meson, but doesn't this contradict with what
> we have in [12/12], part of which says:
> 
> diff --git a/config.mak.uname b/config.mak.uname
> index 2f7d445eb3..0b63be10b7 100644
> --- a/config.mak.uname
> +++ b/config.mak.uname
> @@ -535,7 +535,9 @@ endif
>  		compat/win32/pthread.o compat/win32/syslog.o \
>  		compat/win32/trace2_win32_process_info.o \
>  		compat/win32/dirent.o
> -	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
> +	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY \
> +		-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" -DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\"" \
> +		-DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
>  	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
>  	# invalidcontinue.obj allows Git's source code to close the same file
>  	# handle twice, or to access the osfhandle of an already-closed stdout
> 
> 
> IOW, -DMINGW_PREFIX passed to the compiler strips leading slash from
> $(MINGW_PREFIX).
> 
> Isn't it necessary to strip the leading slash from ming_prefix also
> on the Meson side?

Correct. Since Git for Windows does not use Meson to build the project,
and since the Visual C-based builds (including CI's `windows-meson-build`)
do not use `MSYSTEM`, this was not caught earlier. The next iteration will
have the fix.

Ciao,
Johannes

pathsep = ;
# Assume that this is built in Git for Windows' SDK
ifeq (MINGW32,$(MSYSTEM))
prefix = /mingw32
else
ifeq (CLANGARM64,$(MSYSTEM))
prefix = /clangarm64
else
prefix = /mingw64
endif
ifneq (,$(MSYSTEM))
prefix = $(MINGW_PREFIX)
endif
# Prepend MSVC 64-bit tool-chain to PATH.
#
Expand Down Expand Up @@ -524,7 +518,8 @@ ifeq ($(uname_S),Windows)
NO_POSIX_GOODIES = UnfortunatelyYes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> The "dashed form" has been officially deprecated in Git version 1.5.4,
> which was released on February 2nd, 2008, i.e. a very long time ago.
> This deprecation was never finalized by skipping these hard-links, but
> we can start the process now, in Git for Windows.

Good.  Perhaps somebody (you do not have to volunteer) can champion
their removal from everywhere at Git 3.0 version boundary?

Thanks.

NATIVE_CRLF = YesPlease
DEFAULT_HELP_FORMAT = html
ifeq (/mingw64,$(subst 32,64,$(subst clangarm,mingw,$(prefix))))
SKIP_DASHED_BUILT_INS = YabbaDabbaDoo
ifneq (,$(MINGW_PREFIX))
# Move system config into top-level /etc/
ETC_GITCONFIG = ../etc/gitconfig
ETC_GITATTRIBUTES = ../etc/gitattributes
Expand All @@ -540,7 +535,9 @@ endif
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/trace2_win32_process_info.o \
compat/win32/dirent.o
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY \
-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" -DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\"" \
-DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
# invalidcontinue.obj allows Git's source code to close the same file
# handle twice, or to access the osfhandle of an already-closed stdout
Expand Down Expand Up @@ -716,6 +713,7 @@ ifeq ($(uname_S),MINGW)
FSMONITOR_DAEMON_BACKEND = win32
FSMONITOR_OS_SETTINGS = win32

SKIP_DASHED_BUILT_INS = YabbaDabbaDoo
RUNTIME_PREFIX = YesPlease
HAVE_WPGMPTR = YesWeDo
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
Expand Down Expand Up @@ -754,38 +752,33 @@ ifeq ($(uname_S),MINGW)
ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
BASIC_LDFLAGS += -Wl,--dynamicbase
endif
ifeq (MINGW32,$(MSYSTEM))
prefix = /mingw32
HOST_CPU = i686
BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
endif
ifeq (MINGW64,$(MSYSTEM))
prefix = /mingw64
HOST_CPU = x86_64
BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
else ifeq (CLANGARM64,$(MSYSTEM))
prefix = /clangarm64
HOST_CPU = aarch64
BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
else
COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
BASIC_LDFLAGS += -Wl,--large-address-aware
ifneq (,$(MSYSTEM))
ifeq ($(MINGW_PREFIX),$(filter-out /%,$(MINGW_PREFIX)))
# Override if empty or does not start with a slash
MINGW_PREFIX := /$(shell echo '$(MSYSTEM)' | tr A-Z a-z)
endif
prefix = $(MINGW_PREFIX)
HOST_CPU = $(patsubst %-w64-mingw32,%,$(MINGW_CHOST))
BASIC_LDFLAGS += -Wl,--pic-executable
COMPAT_CFLAGS += -DDETECT_MSYS_TTY \
-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" \
-DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\""
ifeq (MINGW32,$(MSYSTEM))
BASIC_LDFLAGS += -Wl,--large-address-aware
endif
# Move system config into top-level /etc/
ETC_GITCONFIG = ../etc/gitconfig
ETC_GITATTRIBUTES = ../etc/gitattributes
endif
CC = gcc
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
-fstack-protector-strong
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -fstack-protector-strong
EXTLIBS += -lntdll
EXTRA_PROGRAMS += headless-git$X
INSTALL = /bin/install
INTERNAL_QSORT = YesPlease
HAVE_LIBCHARSET_H = YesPlease
USE_GETTEXT_SCHEME = fallthrough
USE_LIBPCRE = YesPlease
ifeq (/mingw64,$(subst 32,64,$(subst clangarm,mingw,$(prefix))))
# Move system config into top-level /etc/
ETC_GITCONFIG = ../etc/gitconfig
ETC_GITATTRIBUTES = ../etc/gitattributes
endif
NO_PYTHON =
endif
ifeq ($(uname_S),QNX)
COMPAT_CFLAGS += -DSA_RESTART=0
Expand Down
9 changes: 8 additions & 1 deletion contrib/buildsystems/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
_CONSOLE DETECT_MSYS_TTY STRIP_EXTENSION=".exe" NO_SYMLINK_HEAD UNRELIABLE_FSTAT
NOGDI OBJECT_CREATION_MODE=1 __USE_MINGW_ANSI_STDIO=0
OVERRIDE_STRDUP MMAP_PREVENTS_DELETE USE_WIN32_MMAP
HAVE_WPGMPTR ENSURE_MSYSTEM_IS_SET HAVE_RTLGENRANDOM)
HAVE_WPGMPTR HAVE_RTLGENRANDOM)
if(CMAKE_GENERATOR_PLATFORM STREQUAL "x64")
add_compile_definitions(ENSURE_MSYSTEM_IS_SET="MINGW64" MINGW_PREFIX="mingw64")
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64")
add_compile_definitions(ENSURE_MSYSTEM_IS_SET="CLANGARM64" MINGW_PREFIX="clangarm64")
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x86")
add_compile_definitions(ENSURE_MSYSTEM_IS_SET="MINGW32" MINGW_PREFIX="mingw32")
endif()
list(APPEND compat_SOURCES
compat/mingw.c
compat/winansi.c
Expand Down
15 changes: 14 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,6 @@ elif host_machine.system() == 'windows'

libgit_c_args += [
'-DDETECT_MSYS_TTY',
'-DENSURE_MSYSTEM_IS_SET',
'-DNATIVE_CRLF',
'-DNOGDI',
'-DNO_POSIX_GOODIES',
Expand All @@ -1328,6 +1327,20 @@ elif host_machine.system() == 'windows'
'-D__USE_MINGW_ANSI_STDIO=0',
]

msystem = get_option('msystem')
if msystem != ''
mingw_prefix = get_option('mingw_prefix')
if mingw_prefix == ''
mingw_prefix = msystem.to_lower()
elif mingw_prefix.startswith('/')
mingw_prefix = mingw_prefix.substring(1)
endif
libgit_c_args += [
'-DENSURE_MSYSTEM_IS_SET="' + msystem + '"',
'-DMINGW_PREFIX="' + mingw_prefix + '"'
]
endif

libgit_dependencies += compiler.find_library('ntdll')
libgit_include_directories += 'compat/win32'
if compiler.get_id() == 'msvc'
Expand Down
4 changes: 4 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ option('runtime_prefix', type: 'boolean', value: false,
description: 'Resolve ancillary tooling and support files relative to the location of the runtime binary instead of hard-coding them into the binary.')
option('sane_tool_path', type: 'array', value: [],
description: 'An array of paths to pick up tools from in case the normal tools are broken or lacking.')
option('msystem', type: 'string', value: '',
description: 'Fall-back on Windows when MSYSTEM is not set.')
option('mingw_prefix', type: 'string', value: '',
description: 'Fall-back on Windows when MINGW_PREFIX is not set.')

# Build information compiled into Git and other parts like documentation.
option('build_date', type: 'string', value: '',
Expand Down
33 changes: 32 additions & 1 deletion t/t0060-path-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,8 @@ test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX wor
echo "echo HERE" | write_script pretend/libexec/git-core/git-here &&
GIT_EXEC_PATH= ./pretend/bin/git here >actual &&
echo HERE >expect &&
test_cmp expect actual'
test_cmp expect actual
'

test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works' '
git config yes.path "%(prefix)/yes" &&
Expand All @@ -611,4 +612,34 @@ test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works'
test_cmp expect actual
'

test_expect_success MINGW,RUNTIME_PREFIX 'MSYSTEM/PATH is adjusted if necessary' '
if test -z "$MINGW_PREFIX"
then
MINGW_PREFIX="/$(echo "${MSYSTEM:-MINGW64}" | tr A-Z a-z)"
fi &&
mkdir -p "$HOME"/bin pretend"$MINGW_PREFIX"/bin \
pretend"$MINGW_PREFIX"/libexec/git-core pretend/usr/bin &&
cp "$GIT_EXEC_PATH"/git.exe pretend"$MINGW_PREFIX"/bin/ &&
cp "$GIT_EXEC_PATH"/git.exe pretend"$MINGW_PREFIX"/libexec/git-core/ &&
# copy the .dll files, if any (happens when building via CMake)
if test -n "$(ls "$GIT_EXEC_PATH"/*.dll 2>/dev/null)"
then
cp "$GIT_EXEC_PATH"/*.dll pretend"$MINGW_PREFIX"/bin/ &&
cp "$GIT_EXEC_PATH"/*.dll pretend"$MINGW_PREFIX"/libexec/git-core/
fi &&
echo "env | grep MSYSTEM=" | write_script "$HOME"/bin/git-test-home &&
echo "echo ${MINGW_PREFIX#/}" | write_script pretend"$MINGW_PREFIX"/bin/git-test-bin &&
echo "echo usr" | write_script pretend/usr/bin/git-test-bin2 &&

(
MSYSTEM= &&
GIT_EXEC_PATH= &&
pretend"$MINGW_PREFIX"/libexec/git-core/git.exe test-home >actual &&
pretend"$MINGW_PREFIX"/libexec/git-core/git.exe test-bin >>actual &&
pretend"$MINGW_PREFIX"/bin/git.exe test-bin2 >>actual
) &&
test_write_lines MSYSTEM=$MSYSTEM "${MINGW_PREFIX#/}" usr >expect &&
test_cmp expect actual
'

test_done
Loading