Skip to contentSkip to conversation

maintenance: do not open console on Windows

PATCH New Derrick Stolee via GitGitGadget 1 participant 3 messages Aug 9, 2023 Kbuild

lore
Share & tools
lore
#0 lore raw

cover maintenance: do not open console on Windows

These two patches are cherry-picks of commits that have lived in git-for-windows/git since 2019 when background maintenance was originally introduced.

If we run the core Git project's version of background maintenance on a Windows platform, then each background maintenance run will create a new console window, visible to the user. This is due to quirks around how Windows applications work: they require some parent application and will create a console window if one does not exist.

This is solved by creating a new 'headless-git.exe' executable that knows how to hide its own window. This isn't an appropriate change to make to 'git.exe' since that expects to be run within an existing console or application.

1. Patch 1 introduces the 'headless-git.exe' executable with the ability to hide its window.
2. Patch 2 modifies the schtasks integration to use 'headless-git.exe' instead of 'git.exe'.

Thanks, -Stolee

Johannes Schindelin (2):
win32: add a helper to run git.exe without a foreground window git maintenance: avoid console window in scheduled tasks on Windows

 Makefile                                   |   9 ++
 builtin/gc.c                               |   2 +-
 compat/win32/headless.c                    | 115 +++++++++++++++++++++
 config.mak.uname                           |   3 +
 contrib/buildsystems/CMakeLists.txt        |   9 ++
 contrib/buildsystems/Generators/Vcxproj.pm |   4 +-
 contrib/buildsystems/engine.pl             |   1 +
 7 files changed, 140 insertions(+), 3 deletions(-)
 create mode 100644 compat/win32/headless.c

base-commit: a82fb66fed250e16d3010c75404503bea3f0ab61
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1570%2Fderrickstolee%2Fheadless-git-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1570/derrickstolee/headless-git-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1570

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH 1/2 win32: add a helper to run `git.exe` without a foreground window

From: Johannes Schindelin <[email protected]>

On Windows, there are two kinds of executables, console ones and non-console ones. Git's executables are all console ones.

When launching the former e.g. in a scheduled task, a CMD window pops up. This is not what we want for the tasks installed via the git maintenance command.

To work around this, let's introduce headless-git.exe, which is a non-console program that does _not_ pop up any window. All it does is to re-launch git.exe, suppressing that console window, passing through all command-line arguments as-are.

---
 Makefile                                   |   9 ++
 compat/win32/headless.c                    | 115 +++++++++++++++++++++
 config.mak.uname                           |   3 +
 contrib/buildsystems/CMakeLists.txt        |   9 ++
 contrib/buildsystems/Generators/Vcxproj.pm |   4 +-
 contrib/buildsystems/engine.pl             |   1 +
 6 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 compat/win32/headless.c
Makefile +9 -0
index fb541dedc9f..15b327b72b9 100644
@@ -2779,6 +2779,13 @@ compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
 compat/nedmalloc/nedmalloc.sp: SP_EXTRA_FLAGS += -Wno-non-pointer-null
 endif
 
+headless-git.o: compat/win32/headless.c GIT-CFLAGS
+	$(QUIET_CC)$(CC) $(ALL_CFLAGS) $(COMPAT_CFLAGS) \
+		-fno-stack-protector -o $@ -c -Wall -Wwrite-strings $<
+
+headless-git$X: headless-git.o git.res GIT-LDFLAGS
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -mwindows -o $@ $< git.res
+
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
@@ -3652,6 +3659,7 @@ clean: profile-clean coverage-clean cocciclean
 	$(RM) po/git.pot po/git-core.pot
 	$(RM) git.res
 	$(RM) $(OBJECTS)
+	$(RM) headless-git.o
 	$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
 	$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
 	$(RM) $(TEST_PROGRAMS)
@@ -3680,6 +3688,7 @@ endif
 	$(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
 ifdef MSVC
 	$(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
+	$(RM) headless-git.o.pdb
 	$(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
 	$(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
 	$(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
compat/win32/headless.c new file +115 -0

115 lines not on this page · raw message

config.mak.uname +3 -0
index 64c44db8058..3bb03f423a0 100644
@@ -526,6 +526,8 @@ else
 endif
 	X = .exe
 
+	EXTRA_PROGRAMS += headless-git$X
+
 compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS
 endif
 ifeq ($(uname_S),Interix)
@@ -705,6 +707,7 @@ ifeq ($(uname_S),MINGW)
 	COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
 		-fstack-protector-strong
 	EXTLIBS += -lntdll
+	EXTRA_PROGRAMS += headless-git$X
 	INSTALL = /bin/install
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
contrib/buildsystems/CMakeLists.txt +9 -0
index 4faa419cc3d..6b819e2fbdf 100644
@@ -738,6 +738,15 @@ if(WIN32)
 	else()
 		message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
 	endif()
+
+	add_executable(headless-git ${CMAKE_SOURCE_DIR}/compat/win32/headless.c)
+	if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
+		target_link_options(headless-git PUBLIC -municode -Wl,-subsystem,windows)
+	elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+		target_link_options(headless-git PUBLIC /NOLOGO /ENTRY:wWinMainCRTStartup /SUBSYSTEM:WINDOWS)
+	else()
+		message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
+	endif()
 elseif(UNIX)
 	target_link_libraries(common-main pthread rt)
 endif()
contrib/buildsystems/Generators/Vcxproj.pm +2 -2
index 1a25789d285..b2e68a16715 100644
@@ -76,7 +76,7 @@ sub createProject {
 
     my $libs_release = "\n    ";
     my $libs_debug = "\n    ";
-    if (!$static_library) {
+    if (!$static_library && $name ne 'headless-git') {
       $libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib|reftable\/libreftable\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}}));
       $libs_debug = $libs_release;
       $libs_debug =~ s/zlib\.lib/zlibd\.lib/g;
@@ -230,7 +230,7 @@ EOM
     print F << "EOM";
   </ItemGroup>
 EOM
-    if (!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') {
+    if ((!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') && !($name =~ /headless-git/)) {
       my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"};
       my $uuid_libreftable = $$build_structure{"LIBS_reftable/libreftable_GUID"};
       my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"};
contrib/buildsystems/engine.pl +1 -0
index ed6c45988a3..069be7e4bef 100755
@@ -371,6 +371,7 @@ sub handleLinkLine
 #    exit(1);
     foreach (@objfiles) {
         my $sourcefile = $_;
+        $sourcefile =~ s/^headless-git\.o$/compat\/win32\/headless.c/;
         $sourcefile =~ s/\.o$/.c/;
         push(@sources, $sourcefile);
         push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}});
Signature · 1 line
gitgitgadget
#2 lore raw

PATCH 2/2 git maintenance: avoid console window in scheduled tasks on Windows

In reply to Derrick Stolee via GitGitGadget

From: Johannes Schindelin <[email protected]>

We just introduced a helper to avoid showing a console window when the scheduled task runs git.exe. Let's actually use it.

---
 builtin/gc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
builtin/gc.c +1 -1
index 19d73067aad..5c4315f0d81 100644
@@ -2068,7 +2068,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
 	      "</Settings>\n"
 	      "<Actions Context=\"Author\">\n"
 	      "<Exec>\n"
-	      "<Command>\"%s\\git.exe\"</Command>\n"
+	      "<Command>\"%s\\headless-git.exe\"</Command>\n"
 	      "<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
 	      "</Exec>\n"
 	      "</Actions>\n"
Signature · 1 line
gitgitgadget