Merge branch 'jh/msvc'
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2019 22:25:45 +0000 (15:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2019 22:25:45 +0000 (15:25 -0700)
Support to build with MSVC has been updated.

* jh/msvc:
msvc: ignore .dll and incremental compile output
msvc: avoid debug assertion windows in Debug Mode
msvc: do not pretend to support all signals
msvc: add pragmas for common warnings
msvc: add a compile-time flag to allow detailed heap debugging
msvc: support building Git using MS Visual C++
msvc: update Makefile to allow for spaces in the compiler path
msvc: fix detect_msys_tty()
msvc: define ftello()
msvc: do not re-declare the timespec struct
msvc: mark a variable as non-const
msvc: define O_ACCMODE
msvc: include sigset_t definition
msvc: fix dependencies of compat/msvc.c
mingw: replace mingw_startup() hack
obstack: fix compiler warning
cache-tree/blame: avoid reusing the DEBUG constant
t0001 (mingw): do not expect a specific order of stdout/stderr
Mark .bat files as requiring CR/LF endings
mingw: fix a typo in the msysGit-specific section

19 files changed:
.gitattributes
.gitignore
Makefile
builtin/blame.c
cache-tree.c
compat/mingw.c
compat/mingw.h
compat/msvc.h
compat/obstack.h
compat/vcbuild/.gitignore [new file with mode: 0644]
compat/vcbuild/README
compat/vcbuild/find_vs_env.bat [new file with mode: 0644]
compat/vcbuild/scripts/clink.pl
compat/vcbuild/vcpkg_copy_dlls.bat [new file with mode: 0644]
compat/vcbuild/vcpkg_install.bat [new file with mode: 0644]
compat/winansi.c
config.mak.uname
git-compat-util.h
t/t0001-init.sh
index 9fa72ad4503031528e24e7c69f24ca92bcc99914..b08a1416d86012134f823fe51443f498f4911909 100644 (file)
@@ -5,6 +5,7 @@
 *.pl eof=lf diff=perl
 *.pm eol=lf diff=perl
 *.py eol=lf diff=python
+*.bat eol=crlf
 /Documentation/**/*.txt eol=lf
 /command-list.txt eol=lf
 /GIT-VERSION-GEN eol=lf
index 40326140c740b57971ba89c5324aaa053d84f8cd..e096e0a51c19966eb743454fab50d232441008ca 100644 (file)
 *.user
 *.idb
 *.pdb
+*.ilk
+*.iobj
+*.ipdb
+*.dll
+.vs/
 /Debug/
 /Release/
 *.dSYM
index a6bbe3c407604192260edaa9ef0a0da04175a05a..98a0588416c4f3f7a5b48ad72a6c2fd54ff94120 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1237,7 +1237,7 @@ endif
 
 ifdef SANE_TOOL_PATH
 SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
-BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix $(SANE_TOOL_PATH_SQ)|'
+BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|'
 PATH := $(SANE_TOOL_PATH):${PATH}
 else
 BROKEN_PATH_FIX = '/^\# @@BROKEN_PATH_FIX@@$$/d'
@@ -2860,6 +2860,33 @@ install: all
        $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
+ifdef MSVC
+       # We DO NOT install the individual foo.o.pdb files because they
+       # have already been rolled up into the exe's pdb file.
+       # We DO NOT have pdb files for the builtin commands (like git-status.exe)
+       # because it is just a copy/hardlink of git.exe, rather than a unique binary.
+       $(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) git-upload-pack.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) git-credential-store.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-fast-import.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-remote-testsvn.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) git-show-index.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+ifndef DEBUG
+       $(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+else
+       $(INSTALL) $(vcpkg_dbg_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) $(vcpkg_dbg_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+endif
+endif
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
        $(INSTALL) -m 644 mergetools/* '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
@@ -3072,6 +3099,19 @@ endif
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
        $(RM) GIT-USER-AGENT GIT-PREFIX
        $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
+ifdef MSVC
+       $(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
+       $(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
+       $(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
+       $(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
+       $(RM) $(patsubst %.exe,%.pdb,$(PROGRAMS))
+       $(RM) $(patsubst %.exe,%.iobj,$(PROGRAMS))
+       $(RM) $(patsubst %.exe,%.ipdb,$(PROGRAMS))
+       $(RM) $(patsubst %.exe,%.pdb,$(TEST_PROGRAMS))
+       $(RM) $(patsubst %.exe,%.iobj,$(TEST_PROGRAMS))
+       $(RM) $(patsubst %.exe,%.ipdb,$(TEST_PROGRAMS))
+       $(RM) compat/vcbuild/MSVC-DEFS-GEN
+endif
 
 .PHONY: all install profile-clean cocciclean clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
index 21cde57e711e337f3c123b35332bb2af0ebdf9cf..50e3d4a2656140b406975947d066283a2ef14460 100644 (file)
@@ -59,8 +59,8 @@ static size_t blame_date_width;
 
 static struct string_list mailmap = STRING_LIST_INIT_NODUP;
 
-#ifndef DEBUG
-#define DEBUG 0
+#ifndef DEBUG_BLAME
+#define DEBUG_BLAME 0
 #endif
 
 static unsigned blame_move_score;
@@ -1062,7 +1062,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        if (blame_copy_score)
                sb.copy_score = blame_copy_score;
 
-       sb.debug = DEBUG;
+       sb.debug = DEBUG_BLAME;
        sb.on_sanity_fail = &sanity_check_on_fail;
 
        sb.show_root = show_root;
index b13bfaf71e9e1554173beca4cfd8acf5929bc9ce..706ffcf1883a01d1ac6f3e966f9d10ebc2e1d8dd 100644 (file)
@@ -6,8 +6,8 @@
 #include "object-store.h"
 #include "replace-object.h"
 
-#ifndef DEBUG
-#define DEBUG 0
+#ifndef DEBUG_CACHE_TREE
+#define DEBUG_CACHE_TREE 0
 #endif
 
 struct cache_tree *cache_tree(void)
@@ -111,7 +111,7 @@ static int do_invalidate_path(struct cache_tree *it, const char *path)
        int namelen;
        struct cache_tree_sub *down;
 
-#if DEBUG
+#if DEBUG_CACHE_TREE
        fprintf(stderr, "cache-tree invalidate <%s>\n", path);
 #endif
 
@@ -398,7 +398,7 @@ static int update_one(struct cache_tree *it,
                strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
                strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz);
 
-#if DEBUG
+#if DEBUG_CACHE_TREE
                fprintf(stderr, "cache-tree update-one %o %.*s\n",
                        mode, entlen, path + baselen);
 #endif
@@ -421,7 +421,7 @@ static int update_one(struct cache_tree *it,
 
        strbuf_release(&buffer);
        it->entry_count = to_invalidate ? -1 : i - *skip_count;
-#if DEBUG
+#if DEBUG_CACHE_TREE
        fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
                it->entry_count, it->subtree_nr,
                oid_to_hex(&it->oid));
@@ -462,7 +462,7 @@ static void write_one(struct strbuf *buffer, struct cache_tree *it,
        strbuf_add(buffer, path, pathlen);
        strbuf_addf(buffer, "%c%d %d\n", 0, it->entry_count, it->subtree_nr);
 
-#if DEBUG
+#if DEBUG_CACHE_TREE
        if (0 <= it->entry_count)
                fprintf(stderr, "cache-tree <%.*s> (%d ent, %d subtree) %s\n",
                        pathlen, path, it->entry_count, it->subtree_nr,
@@ -536,7 +536,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
                size -= rawsz;
        }
 
-#if DEBUG
+#if DEBUG_CACHE_TREE
        if (0 <= it->entry_count)
                fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n",
                        *buffer, it->entry_count, subtree_nr,
index 9b6d2400e1107fa2a65f6ecd7d067809115930b9..433838391fd95d6c89279561df63176f31d77b27 100644 (file)
@@ -1553,7 +1553,10 @@ static int try_shell_exec(const char *cmd, char *const *argv)
        if (prog) {
                int exec_id;
                int argc = 0;
-               const char **argv2;
+#ifndef _MSC_VER
+               const
+#endif
+               char **argv2;
                while (argv[argc]) argc++;
                ALLOC_ARRAY(argv2, argc + 1);
                argv2[0] = (char *)cmd; /* full path to the script file */
@@ -2116,8 +2119,33 @@ int mingw_raise(int sig)
                        sigint_fn(SIGINT);
                return 0;
 
+#if defined(_MSC_VER)
+       case SIGILL:
+       case SIGFPE:
+       case SIGSEGV:
+       case SIGTERM:
+       case SIGBREAK:
+       case SIGABRT:
+       case SIGABRT_COMPAT:
+               /*
+                * The <signal.h> header in the MS C Runtime defines 8 signals
+                * as being supported on the platform. Anything else causes an
+                * "Invalid signal or error" (which in DEBUG builds causes the
+                * Abort/Retry/Ignore dialog). We by-pass the CRT for things we
+                * already know will fail.
+                */
+               return raise(sig);
+       default:
+               errno = EINVAL;
+               return -1;
+
+#else
+
        default:
                return raise(sig);
+
+#endif
+
        }
 }
 
@@ -2301,18 +2329,13 @@ static void setup_windows_environment(void)
                setenv("TERM", "cygwin", 1);
 }
 
+#if !defined(_MSC_VER)
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
  */
 int _CRT_glob = 0;
-
-typedef struct {
-       int newmode;
-} _startupinfo;
-
-extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
-               _startupinfo *si);
+#endif
 
 static NORETURN void die_startup(void)
 {
@@ -2390,21 +2413,40 @@ static void maybe_redirect_std_handles(void)
                                  GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
 }
 
-void mingw_startup(void)
+#ifdef _MSC_VER
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+#endif
+
+/*
+ * We implement wmain() and compile with -municode, which would
+ * normally ignore main(), but we call the latter from the former
+ * so that we can handle non-ASCII command-line parameters
+ * appropriately.
+ *
+ * To be more compatible with the core git code, we convert
+ * argv into UTF8 and pass them directly to main().
+ */
+int wmain(int argc, const wchar_t **wargv)
 {
-       int i, maxlen, argc;
-       char *buffer;
-       wchar_t **wenv, **wargv;
-       _startupinfo si;
+       int i, maxlen, exit_status;
+       char *buffer, **save;
+       const char **argv;
 
        trace2_initialize_clock();
 
-       maybe_redirect_std_handles();
+#ifdef _MSC_VER
+#ifdef _DEBUG
+       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+#endif
 
-       /* get wide char arguments and environment */
-       si.newmode = 0;
-       if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
-               die_startup();
+#ifdef USE_MSVC_CRTDBG
+       _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+#endif
+
+       maybe_redirect_std_handles();
 
        /* determine size of argv and environ conversion buffer */
        maxlen = wcslen(wargv[0]);
@@ -2415,9 +2457,16 @@ void mingw_startup(void)
        maxlen = 3 * maxlen + 1;
        buffer = malloc_startup(maxlen);
 
-       /* convert command line arguments and environment to UTF-8 */
+       /*
+        * Create a UTF-8 version of w_argv. Also create a "save" copy
+        * to remember all the string pointers because parse_options()
+        * will remove claimed items from the argv that we pass down.
+        */
+       ALLOC_ARRAY(argv, argc + 1);
+       ALLOC_ARRAY(save, argc + 1);
        for (i = 0; i < argc; i++)
-               __argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+               argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+       argv[i] = save[i] = NULL;
        free(buffer);
 
        /* fix Windows specific environment settings */
@@ -2436,6 +2485,16 @@ void mingw_startup(void)
 
        /* initialize Unicode console */
        winansi_init();
+
+       /* invoke the real main() using our utf8 version of argv. */
+       exit_status = main(argc, argv);
+
+       for (i = 0; i < argc; i++)
+               free(save[i]);
+       free(save);
+       free(argv);
+
+       return exit_status;
 }
 
 int uname(struct utsname *buf)
index 593bdbffe68060e3cfd73fc8e3b2b0ffbc5faf64..a03e40e6e2a6cba13ed1fed2d4d690443fcd40a8 100644 (file)
@@ -352,11 +352,13 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
 #ifndef __MINGW64_VERSION_MAJOR
 #define off_t off64_t
 #define lseek _lseeki64
+#ifndef _MSC_VER
 struct timespec {
        time_t tv_sec;
        long tv_nsec;
 };
 #endif
+#endif
 
 struct mingw_stat {
     _dev_t st_dev;
@@ -562,18 +564,18 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
 extern CRITICAL_SECTION pinfo_cs;
 
 /*
- * A replacement of main() that adds win32 specific initialization.
+ * Git, like most portable C applications, implements a main() function. On
+ * Windows, this main() function would receive parameters encoded in the
+ * current locale, but Git for Windows would prefer UTF-8 encoded  parameters.
+ *
+ * To make that happen, we still declare main() here, and then declare and
+ * implement wmain() (which is the Unicode variant of main()) and compile with
+ * -municode. This wmain() function reencodes the parameters from UTF-16 to
+ * UTF-8 format, sets up a couple of other things as required on Windows, and
+ * then hands off to the main() function.
  */
-
-void mingw_startup(void);
-#define main(c,v) dummy_decl_mingw_main(void); \
-static int mingw_main(c,v); \
-int main(int argc, const char **argv) \
-{ \
-       mingw_startup(); \
-       return mingw_main(__argc, (void *)__argv); \
-} \
-static int mingw_main(c,v)
+int wmain(int argc, const wchar_t **w_argv);
+int main(int argc, const char **argv);
 
 /*
  * Used by Pthread API implementation for Windows
index 29a8ce820435d5c67dd5fd9bc23dab0c2e7d8394..1d7a8c614565a6088f92f7c06d79210476ce505e 100644 (file)
@@ -6,6 +6,10 @@
 #include <malloc.h>
 #include <io.h>
 
+#pragma warning(disable: 4018) /* signed/unsigned comparison */
+#pragma warning(disable: 4244) /* type conversion, possible loss of data */
+#pragma warning(disable: 4090) /* 'function' : different 'const' qualifiers (ALLOC_GROW etc.)*/
+
 /* porting function */
 #define inline __inline
 #define __inline__ __inline
 
 #undef ERROR
 
+#define ftello _ftelli64
+
+typedef int sigset_t;
+/* open for reading, writing, or both (not in fcntl.h) */
+#define O_ACCMODE     (_O_RDONLY | _O_WRONLY | _O_RDWR)
+
 #include "compat/mingw.h"
 
 #endif
index ced94d01180a66b2f2d471c1ebaef4eec07e6c49..ae36ed6a669d96266f01f4983b9d6a418e1dcfef 100644 (file)
@@ -496,7 +496,7 @@ __extension__                                                               \
 ( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk,            \
   ((((h)->temp.tempint > 0                                             \
     && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk))    \
-   ? (int) ((h)->next_free = (h)->object_base                          \
+   ? (ptrdiff_t) ((h)->next_free = (h)->object_base                            \
            = (h)->temp.tempint + (char *) (h)->chunk)                  \
    : (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0)))
 
diff --git a/compat/vcbuild/.gitignore b/compat/vcbuild/.gitignore
new file mode 100644 (file)
index 0000000..8f8b794
--- /dev/null
@@ -0,0 +1,3 @@
+/vcpkg/
+/MSVC-DEFS-GEN
+/VCPKG-DEFS
index 60fd873fe801da608cdef1ac2bafd371a0855db0..b633e7db983d5095d8a1b9ecfb7a66dbdb4d9c3b 100644 (file)
@@ -1,3 +1,42 @@
+The Steps to Build Git with VS2015 or VS2017 from the command line.
+
+1. Install the "vcpkg" open source package manager and build essential
+   third-party libraries.  The steps for this have been captured in a
+   set of convenience scripts.  These can be run from a stock Command
+   Prompt or from an SDK bash window:
+
+   $ cd <repo_root>
+   $ ./compat/vcbuild/vcpkg_install.bat
+
+   The vcpkg tools and all of the third-party sources will be installed
+   in this folder:
+      <repo_root>/compat/vcbuild/vcpkg/
+
+   A file will be created with a set of Makefile macros pointing to a
+   unified "include", "lib", and "bin" directory (release and debug) for
+   all of the required packages.  This file will be included by the main
+   Makefile:
+      <repo_root>/compat/vcbuild/MSVC-DEFS-GEN
+
+2. OPTIONALLY copy the third-party *.dll and *.pdb files into the repo
+   root to make it easier to run and debug git.exe without having to
+   manipulate your PATH.  This is especially true for debug sessions in
+   Visual Studio.
+
+   Use ONE of the following forms which should match how you want to
+   compile git.exe.
+
+   $ ./compat/vcbuild/vcpkg_copy_packages.bat debug
+   $ ./compat/vcbuild/vcpkg_copy_packages.bat release
+
+3. Build git using MSVC from an SDK bash window using one of the
+   following commands:
+
+   $ make MSVC=1
+   $ make MSVC=1 DEBUG=1
+
+================================================================
+
 The Steps of Build Git with VS2008
 
 1. You need the build environment, which contains the Git dependencies
diff --git a/compat/vcbuild/find_vs_env.bat b/compat/vcbuild/find_vs_env.bat
new file mode 100644 (file)
index 0000000..40194dd
--- /dev/null
@@ -0,0 +1,168 @@
+@ECHO OFF
+REM ================================================================
+REM You can use either GCC (the default) or MSVC to build git
+REM using the GIT-SDK command line tools.
+REM        $ make
+REM        $ make MSVC=1
+REM
+REM GIT-SDK BASH windows inherit environment variables with all of
+REM the bin/lib/include paths for GCC.  It DOES NOT inherit values
+REM for the corresponding MSVC tools.
+REM
+REM During normal (non-git) Windows development, you launch one
+REM of the provided "developer command prompts" to set environment
+REM variables for the MSVC tools.
+REM
+REM Therefore, to allow MSVC command line builds of git from BASH
+REM and MAKE, we must blend these two different worlds.  This script
+REM attempts to do that.
+REM ================================================================
+REM This BAT file starts in a plain (non-developer) command prompt,
+REM searches for the "best" commmand prompt setup script, installs
+REM it into the current CMD process, and exports the various MSVC
+REM environment variables for use by MAKE.
+REM
+REM The output of this script should be written to a make "include
+REM file" and referenced by the top-level Makefile.
+REM
+REM See "config.mak.uname" (look for compat/vcbuild/MSVC-DEFS-GEN).
+REM ================================================================
+REM The provided command prompts are custom to each VS release and
+REM filled with lots of internal knowledge (such as Registry settings);
+REM even their names vary by release, so it is not appropriate for us
+REM to look inside them.  Rather, just run them in a subordinate
+REM process and extract the settings we need.
+REM ================================================================
+REM
+REM Current (VS2017 and beyond)
+REM -------------------
+REM Visual Studio 2017 introduced a new installation layout and
+REM support for side-by-side installation of multiple versions of
+REM VS2017.  Furthermore, these can all coexist with installations
+REM of previous versions of VS (which have a completely different
+REM layout on disk).
+REM
+REM VS2017 Update 2 introduced a "vswhere.exe" command:
+REM https://github.com/Microsoft/vswhere
+REM https://blogs.msdn.microsoft.com/heaths/2017/02/25/vswhere-available/
+REM https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
+REM
+REM VS2015
+REM ------
+REM Visual Studio 2015 uses the traditional VcVarsAll.
+REM
+REM Earlier Versions
+REM ----------------
+REM Currently unsupported.
+REM
+REM ================================================================
+REM Note: Throughout this script we use "dir <path> && <cmd>" rather
+REM than "if exist <path>" because of script problems with pathnames
+REM containing spaces.
+REM ================================================================
+
+REM Sanitize PATH to prevent git-sdk paths from confusing "wmic.exe"
+REM (called internally in some of the system BAT files).
+SET PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;
+
+REM ================================================================
+
+:current
+   SET vs_where=C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe
+   dir "%vs_where%" >nul 2>nul && GOTO have_vs_where
+   GOTO not_2017
+
+:have_vs_where
+   REM Try to use VsWhere to get the location of VsDevCmd.
+
+   REM Keep VsDevCmd from cd'ing away.
+   SET VSCMD_START_DIR=.
+
+   REM Get the root of the VS product installation.
+   FOR /F "usebackq tokens=*" %%i IN (`"%vs_where%" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath`) DO @SET vs_ip=%%i
+
+   SET vs_devcmd=%vs_ip%\Common7\Tools\VsDevCmd.bat
+   dir "%vs_devcmd%" >nul 2>nul && GOTO have_vs_devcmd
+   GOTO not_2017
+
+:have_vs_devcmd
+   REM Use VsDevCmd to setup the environment of this process.
+   REM Setup CL for building 64-bit apps using 64-bit tools.
+   @call "%vs_devcmd%" -no_logo -arch=x64 -host_arch=x64
+
+   SET tgt=%VSCMD_ARG_TGT_ARCH%
+
+   SET mn=%VCToolsInstallDir%
+   SET msvc_includes=-I"%mn%INCLUDE"
+   SET msvc_libs=-L"%mn%lib\%tgt%"
+   SET msvc_bin_dir=%mn%bin\Host%VSCMD_ARG_HOST_ARCH%\%tgt%
+
+   SET sdk_dir=%WindowsSdkDir%
+   SET sdk_ver=%WindowsSDKVersion%
+   SET si=%sdk_dir%Include\%sdk_ver%
+   SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared"
+   SET sl=%sdk_dir%lib\%sdk_ver%
+   SET sdk_libs=-L"%sl%ucrt\%tgt%" -L"%sl%um\%tgt%"
+
+   SET vs_ver=%VisualStudioVersion%
+
+   GOTO print_vars
+
+REM ================================================================
+
+:not_2017
+   REM See if VS2015 is installed.
+
+   SET vs_2015_bat=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
+   dir "%vs_2015_bat%" >nul 2>nul && GOTO have_vs_2015
+   GOTO not_2015
+
+:have_vs_2015
+   REM Use VcVarsAll like the "x64 Native" command prompt.
+   REM Setup CL for building 64-bit apps using 64-bit tools.
+   @call "%vs_2015_bat%" amd64
+
+   REM Note that in VS2015 they use "x64" in some contexts and "amd64" in others.
+   SET mn=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
+   SET msvc_includes=-I"%mn%INCLUDE"
+   SET msvc_libs=-L"%mn%lib\amd64"
+   SET msvc_bin_dir=%mn%bin\amd64
+
+   SET sdk_dir=%WindowsSdkDir%
+   SET sdk_ver=%WindowsSDKVersion%
+   SET si=%sdk_dir%Include\%sdk_ver%
+   SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared" -I"%si%winrt"
+   SET sl=%sdk_dir%lib\%sdk_ver%
+   SET sdk_libs=-L"%sl%ucrt\x64" -L"%sl%um\x64"
+
+   SET vs_ver=%VisualStudioVersion%
+
+   GOTO print_vars
+
+REM ================================================================
+
+:not_2015
+   echo "ERROR: unsupported VS version (older than VS2015)" >&2
+   EXIT /B 1
+
+REM ================================================================
+
+:print_vars
+   REM Dump the essential vars to stdout to allow the main
+   REM Makefile to include it.  See config.mak.uname.
+   REM Include DOS-style and BASH-style path for bin dir.
+
+   echo msvc_bin_dir=%msvc_bin_dir%
+   SET X1=%msvc_bin_dir:C:=/C%
+   SET X2=%X1:\=/%
+   echo msvc_bin_dir_msys=%X2%
+
+   echo msvc_includes=%msvc_includes%
+   echo msvc_libs=%msvc_libs%
+
+   echo sdk_includes=%sdk_includes%
+   echo sdk_libs=%sdk_libs%
+
+   echo vs_ver=%vs_ver%
+
+   EXIT /B 0
index a87d0da512e095ad261bef868a866a7e6f5e3bef..c7b021bfac7a46bc0ee135cc5e543331839c6f7b 100755 (executable)
 use strict;
 my @args = ();
 my @cflags = ();
+my @lflags = ();
 my $is_linking = 0;
+my $is_debug = 0;
 while (@ARGV) {
        my $arg = shift @ARGV;
-       if ("$arg" =~ /^-[DIMGO]/) {
+       if ("$arg" eq "-DDEBUG") {
+           # Some vcpkg-based libraries have different names for release
+           # and debug versions.  This hack assumes that -DDEBUG comes
+           # before any "-l*" flags.
+           $is_debug = 1;
+       }
+       if ("$arg" =~ /^-[DIMGOZ]/) {
                push(@cflags, $arg);
        } elsif ("$arg" eq "-o") {
                my $file_out = shift @ARGV;
                if ("$file_out" =~ /exe$/) {
                        $is_linking = 1;
+                       # Create foo.exe and foo.pdb
                        push(@args, "-OUT:$file_out");
                } else {
+                       # Create foo.o and foo.o.pdb
                        push(@args, "-Fo$file_out");
+                       push(@args, "-Fd$file_out.pdb");
                }
        } elsif ("$arg" eq "-lz") {
+           if ($is_debug) {
+               push(@args, "zlibd.lib");
+           } else{
                push(@args, "zlib.lib");
+           }
        } elsif ("$arg" eq "-liconv") {
-               push(@args, "iconv.lib");
+               push(@args, "libiconv.lib");
        } elsif ("$arg" eq "-lcrypto") {
                push(@args, "libeay32.lib");
        } elsif ("$arg" eq "-lssl") {
                push(@args, "ssleay32.lib");
        } elsif ("$arg" eq "-lcurl") {
-               push(@args, "libcurl.lib");
+               my $lib = "";
+               # Newer vcpkg definitions call this libcurl_imp.lib; Do we
+               # need to use that instead?
+               foreach my $flag (@lflags) {
+                       if ($flag =~ /^-LIBPATH:(.*)/) {
+                               foreach my $l ("libcurl_imp.lib", "libcurl.lib") {
+                                       if (-f "$1/$l") {
+                                               $lib = $l;
+                                               last;
+                                       }
+                               }
+                       }
+               }
+               push(@args, $lib);
+       } elsif ("$arg" eq "-lexpat") {
+               push(@args, "expat.lib");
        } elsif ("$arg" =~ /^-L/ && "$arg" ne "-LTCG") {
                $arg =~ s/^-L/-LIBPATH:/;
-               push(@args, $arg);
+               push(@lflags, $arg);
        } elsif ("$arg" =~ /^-R/) {
                # eat
        } else {
        }
 }
 if ($is_linking) {
+       push(@args, @lflags);
        unshift(@args, "link.exe");
 } else {
        unshift(@args, "cl.exe");
        push(@args, @cflags);
 }
-#printf("**** @args\n");
+printf(STDERR "**** @args\n\n\n") if (!defined($ENV{'QUIET_GEN'}));
 exit (system(@args) != 0);
diff --git a/compat/vcbuild/vcpkg_copy_dlls.bat b/compat/vcbuild/vcpkg_copy_dlls.bat
new file mode 100644 (file)
index 0000000..13661c1
--- /dev/null
@@ -0,0 +1,39 @@
+@ECHO OFF
+REM ================================================================
+REM This script is an optional step. It copies the *.dll and *.pdb
+REM files (created by vcpkg_install.bat) into the top-level directory
+REM of the repo so that you can type "./git.exe" and find them without
+REM having to fixup your PATH.
+REM
+REM NOTE: Because the names of some DLL files change between DEBUG and
+REM NOTE: RELEASE builds when built using "vcpkg.exe", you will need
+REM NOTE: to copy up the corresponding version.
+REM ================================================================
+
+       SETLOCAL EnableDelayedExpansion
+
+       @FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
+       cd %cwd%
+
+       SET arch=x64-windows
+       SET inst=%cwd%vcpkg\installed\%arch%
+
+       IF [%1]==[release] (
+               echo Copying RELEASE mode DLLs to repo root...
+       ) ELSE IF [%1]==[debug] (
+               SET inst=%inst%\debug
+               echo Copying DEBUG mode DLLs to repo root...
+       ) ELSE (
+               echo ERROR: Invalid argument.
+               echo Usage: %~0 release
+               echo Usage: %~0 debug
+               EXIT /B 1
+       )
+
+       xcopy /e/s/v/y %inst%\bin\*.dll ..\..\
+       xcopy /e/s/v/y %inst%\bin\*.pdb ..\..\
+
+       xcopy /e/s/v/y %inst%\bin\*.dll ..\..\t\helper\
+       xcopy /e/s/v/y %inst%\bin\*.pdb ..\..\t\helper\
+
+       EXIT /B 0
diff --git a/compat/vcbuild/vcpkg_install.bat b/compat/vcbuild/vcpkg_install.bat
new file mode 100644 (file)
index 0000000..ebd0bad
--- /dev/null
@@ -0,0 +1,80 @@
+@ECHO OFF
+REM ================================================================
+REM This script installs the "vcpkg" source package manager and uses
+REM it to build the third-party libraries that git requires when it
+REM is built using MSVC.
+REM
+REM [1] Install VCPKG.
+REM     [a] Create <root>/compat/vcbuild/vcpkg/
+REM     [b] Download "vcpkg".
+REM     [c] Compile using the currently installed version of VS.
+REM     [d] Create <root>/compat/vcbuild/vcpkg/vcpkg.exe
+REM
+REM [2] Install third-party libraries.
+REM     [a] Download each (which may also install CMAKE).
+REM     [b] Compile in RELEASE mode and install in:
+REM         vcpkg/installed/<arch>/{bin,lib}
+REM     [c] Compile in DEBUG mode and install in:
+REM         vcpkg/installed/<arch>/debug/{bin,lib}
+REM     [d] Install headers in:
+REM         vcpkg/installed/<arch>/include
+REM
+REM [3] Create a set of MAKE definitions for the top-level
+REM     Makefile to allow "make MSVC=1" to find the above
+REM     third-party libraries.
+REM     [a] Write vcpkg/VCPGK-DEFS
+REM
+REM https://blogs.msdn.microsoft.com/vcblog/2016/09/19/vcpkg-a-tool-to-acquire-and-build-c-open-source-libraries-on-windows/
+REM https://github.com/Microsoft/vcpkg
+REM https://vcpkg.readthedocs.io/en/latest/
+REM ================================================================
+
+       SETLOCAL EnableDelayedExpansion
+
+       @FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
+       cd %cwd%
+
+       dir vcpkg\vcpkg.exe >nul 2>nul && GOTO :install_libraries
+
+       echo Fetching vcpkg in %cwd%vcpkg
+       git.exe clone https://github.com/Microsoft/vcpkg vcpkg
+       IF ERRORLEVEL 1 ( EXIT /B 1 )
+
+       cd vcpkg
+       echo Building vcpkg
+       powershell -exec bypass scripts\bootstrap.ps1
+       IF ERRORLEVEL 1 ( EXIT /B 1 )
+
+       echo Successfully installed %cwd%vcpkg\vcpkg.exe
+
+:install_libraries
+       SET arch=x64-windows
+
+       echo Installing third-party libraries...
+       FOR %%i IN (zlib expat libiconv openssl libssh2 curl) DO (
+           cd %cwd%vcpkg
+           IF NOT EXIST "packages\%%i_%arch%" CALL :sub__install_one %%i
+           IF ERRORLEVEL 1 ( EXIT /B 1 )
+       )
+
+:install_defines
+       cd %cwd%
+       SET inst=%cwd%vcpkg\installed\%arch%
+
+       echo vcpkg_inc=-I"%inst%\include">VCPKG-DEFS
+       echo vcpkg_rel_lib=-L"%inst%\lib">>VCPKG-DEFS
+       echo vcpkg_rel_bin="%inst%\bin">>VCPKG-DEFS
+       echo vcpkg_dbg_lib=-L"%inst%\debug\lib">>VCPKG-DEFS
+       echo vcpkg_dbg_bin="%inst%\debug\bin">>VCPKG-DEFS
+
+       EXIT /B 0
+
+
+:sub__install_one
+       echo     Installing package %1...
+
+       .\vcpkg.exe install %1:%arch%
+       IF ERRORLEVEL 1 ( EXIT /B 1 )
+
+       echo     Finished %1
+       goto :EOF
index a29d34ef44864f02bd89c8490d38bca0efe2a8e6..efc0abcdac43e1c126d6d8148b8a03392e4ae911 100644 (file)
@@ -540,7 +540,20 @@ static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
 #ifdef DETECT_MSYS_TTY
 
 #include <winternl.h>
+
+#if defined(_MSC_VER)
+
+typedef struct _OBJECT_NAME_INFORMATION
+{
+       UNICODE_STRING Name;
+       WCHAR NameBuffer[0];
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+#define ObjectNameInformation 1
+
+#else
 #include <ntstatus.h>
+#endif
 
 static void detect_msys_tty(int fd)
 {
index b71688eeb73f10da004f3d16e3de9afd13eb9c7e..3fde48c64da61c6964ea5584aa5c27ec5dcbc389 100644 (file)
@@ -1,5 +1,9 @@
 # Platform specific Makefile tweaks based on uname detection
 
+# Define NO_SAFESEH if you need MSVC/Visual Studio to ignore the lack of
+# Microsoft's Safe Exception Handling in libraries (such as zlib).
+# Typically required for VS2013+/32-bit compilation on Vista+ versions.
+
 uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
 uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
 uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
@@ -11,6 +15,19 @@ ifdef MSVC
        # avoid the MingW and Cygwin configuration sections
        uname_S := Windows
        uname_O := Windows
+
+       # Generate and include makefile variables that point to the
+       # currently installed set of MSVC command line tools.
+compat/vcbuild/MSVC-DEFS-GEN: compat/vcbuild/find_vs_env.bat
+       @"$<" | tr '\\' / >"$@"
+include compat/vcbuild/MSVC-DEFS-GEN
+
+       # See if vcpkg and the vcpkg-build versions of the third-party
+       # libraries that we use are installed.  We include the result
+       # to get $(vcpkg_*) variables defined for the Makefile.
+compat/vcbuild/VCPKG-DEFS: compat/vcbuild/vcpkg_install.bat
+       @"$<"
+include compat/vcbuild/VCPKG-DEFS
 endif
 
 # We choose to avoid "if .. else if .. else .. endif endif"
@@ -356,6 +373,19 @@ endif
 ifeq ($(uname_S),Windows)
        GIT_VERSION := $(GIT_VERSION).MSVC
        pathsep = ;
+       # Assume that this is built in Git for Windows' SDK
+       ifeq (MINGW32,$(MSYSTEM))
+               prefix = /mingw32
+       else
+               prefix = /mingw64
+       endif
+       # Prepend MSVC 64-bit tool-chain to PATH.
+       #
+       # A regular Git Bash *does not* have cl.exe in its $PATH. As there is a
+       # link.exe next to, and required by, cl.exe, we have to prepend this
+       # onto the existing $PATH.
+       #
+       SANE_TOOL_PATH ?= $(msvc_bin_dir_msys)
        HAVE_ALLOCA_H = YesPlease
        NO_PREAD = YesPlease
        NEEDS_CRYPTO_WITH_SSL = YesPlease
@@ -368,11 +398,14 @@ ifeq ($(uname_S),Windows)
        NO_STRCASESTR = YesPlease
        NO_STRLCPY = YesPlease
        NO_MEMMEM = YesPlease
-       # NEEDS_LIBICONV = YesPlease
-       NO_ICONV = YesPlease
+       NEEDS_LIBICONV = YesPlease
        NO_STRTOUMAX = YesPlease
        NO_MKDTEMP = YesPlease
-       SNPRINTF_RETURNS_BOGUS = YesPlease
+       NO_INTTYPES_H = YesPlease
+       # VS2015 with UCRT claims that snprintf and friends are C99 compliant,
+       # so we don't need this:
+       #
+       #   SNPRINTF_RETURNS_BOGUS = YesPlease
        NO_SVN_TESTS = YesPlease
        RUNTIME_PREFIX = YesPlease
        HAVE_WPGMPTR = YesWeDo
@@ -385,7 +418,6 @@ ifeq ($(uname_S),Windows)
        NO_REGEX = YesPlease
        NO_GETTEXT = YesPlease
        NO_PYTHON = YesPlease
-       BLK_SHA1 = YesPlease
        ETAGS_TARGET = ETAGS
        NO_POSIX_GOODIES = UnfortunatelyYes
        NATIVE_CRLF = YesPlease
@@ -394,26 +426,52 @@ ifeq ($(uname_S),Windows)
        CC = compat/vcbuild/scripts/clink.pl
        AR = compat/vcbuild/scripts/lib.pl
        CFLAGS =
-       BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
+       BASIC_CFLAGS = -nologo -I. -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
        COMPAT_OBJS = compat/msvc.o compat/winansi.o \
                compat/win32/path-utils.o \
                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 -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-       BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
-       EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj
+       COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -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
+       # See https://msdn.microsoft.com/en-us/library/ms235330.aspx
+       EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj kernel32.lib ntdll.lib
        PTHREAD_LIBS =
        lib =
+       BASIC_CFLAGS += $(vcpkg_inc) $(sdk_includes) $(msvc_includes)
+ifndef DEBUG
+       BASIC_CFLAGS += $(vcpkg_rel_lib)
+else
+       BASIC_CFLAGS += $(vcpkg_dbg_lib)
+endif
+       BASIC_CFLAGS += $(sdk_libs) $(msvc_libs)
+
+ifneq ($(USE_MSVC_CRTDBG),)
+       # Optionally enable memory leak reporting.
+       BASIC_CFLAGS += -DUSE_MSVC_CRTDBG
+endif
        BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
+       # Always give "-Zi" to the compiler and "-debug" to linker (even in
+       # release mode) to force a PDB to be generated (like RelWithDebInfo).
+       BASIC_CFLAGS += -Zi
+       BASIC_LDFLAGS += -debug -Zf
+
+ifdef NO_SAFESEH
+       LDFLAGS += -SAFESEH:NO
+endif
+
 ifndef DEBUG
-       BASIC_CFLAGS += -GL -Os -MD
-       BASIC_LDFLAGS += -LTCG
+       BASIC_CFLAGS += -GL -Gy -O2 -Oy- -MD -DNDEBUG
+       BASIC_LDFLAGS += -release -LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO /DEBUGTYPE:CV,FIXUP
        AR += -LTCG
 else
-       BASIC_CFLAGS += -Zi -MDd
+       BASIC_CFLAGS += -MDd -DDEBUG -D_DEBUG
 endif
        X = .exe
+
+compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS
 endif
 ifeq ($(uname_S),Interix)
        NO_INITGROUPS = YesPlease
@@ -548,6 +606,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        ETAGS_TARGET = ETAGS
        NO_POSIX_GOODIES = UnfortunatelyYes
        DEFAULT_HELP_FORMAT = html
+       BASIC_LDFLAGS += -municode
        COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/winansi.o \
@@ -571,7 +630,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
        INTERNAL_QSORT = YesPlease
        HAVE_LIBCHARSET_H = YesPlease
        NO_GETTEXT = YesPlease
-       COMPAT_CLFAGS += -D__USE_MINGW_ACCESS
+       COMPAT_CFLAGS += -D__USE_MINGW_ACCESS
 else
        ifneq ($(shell expr "$(uname_R)" : '1\.'),2)
                # MSys2
index cc0e7e97334ec90a355f9c8eb088c6810a91193c..83be89de0aac7c96799635e3b2858a465f440acf 100644 (file)
@@ -1,6 +1,15 @@
 #ifndef GIT_COMPAT_UTIL_H
 #define GIT_COMPAT_UTIL_H
 
+#ifdef USE_MSVC_CRTDBG
+/*
+ * For these to work they must appear very early in each
+ * file -- before most of the standard header files.
+ */
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+
 #define _FILE_OFFSET_BITS 64
 
 
index 77c5ed6a18e7849c4b823f9056dfb34cca951e15..26f82063267f3043f7f9c36745d913c12dbe0a27 100755 (executable)
@@ -467,8 +467,8 @@ test_expect_success MINGW 'redirect std handles' '
                GIT_REDIRECT_STDOUT=output.txt \
                GIT_REDIRECT_STDERR="2>&1" \
                git rev-parse --git-dir --verify refs/invalid &&
-       printf ".git\nfatal: Needed a single revision\n" >expect &&
-       test_cmp expect output.txt
+       grep "^\\.git\$" output.txt &&
+       grep "Needed a single revision" output.txt
 '
 
 test_done