Skip to content

Commit 5d3ca0a

Browse files
jeffhostetlerdscho
authored andcommitted
msvc: support building Git using MS Visual C++
With this patch, Git can be built using the Microsoft toolchain, via: make MSVC=1 [DEBUG=1] Third party libraries are built from source using the open source "vcpkg" tool set. See https://github.com/Microsoft/vcpkg On a first build, the vcpkg tools and the third party libraries are automatically downloaded and built. DLLs for the third party libraries are copied to the top-level (and t/helper) directory to facilitate debugging. See compat/vcbuild/README. A series of .bat files are invoked by the Makefile to find the location of the installed version of Visual Studio and the associated compiler tools (essentially replicating the environment setup performed by a "Developer Command Prompt"). This should find the most recent VS2015 or VS2017 installation. Output from these scripts are used by the Makefile to define compiler and linker pathnames and -I and -L arguments. The build produces .pdb files for both debug and release builds. Note: This commit was squashed from an organic series of commits developed between 2016 and 2018 in Git for Windows' `master` branch. This combined commit eliminates the obsolete commits related to fetching NuGet packages for third party libraries. It is difficult to use NuGet packages for C/C++ sources because they may be built by earlier versions of the MSVC compiler and have CRT version and linking issues. Additionally, the C/C++ NuGet packages that were using tended to not be updated concurrently with the sources. And in the case of cURL and OpenSSL, this could expose us to security issues. Helped-by: Yue Lin Ho <[email protected]> Helped-by: Philip Oakley <[email protected]> Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent b2d6eb9 commit 5d3ca0a

File tree

10 files changed

+491
-15
lines changed

10 files changed

+491
-15
lines changed

Makefile

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@ endif
11791179

11801180
ifdef SANE_TOOL_PATH
11811181
SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
1182-
BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix $(SANE_TOOL_PATH_SQ)|'
1182+
BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|'
11831183
PATH := $(SANE_TOOL_PATH):${PATH}
11841184
else
11851185
BROKEN_PATH_FIX = '/^\# @@BROKEN_PATH_FIX@@$$/d'
@@ -2749,6 +2749,33 @@ install: all
27492749
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
27502750
$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
27512751
$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
2752+
ifdef MSVC
2753+
# We DO NOT install the individual foo.o.pdb files because they
2754+
# have already been rolled up into the exe's pdb file.
2755+
# We DO NOT have pdb files for the builtin commands (like git-status.exe)
2756+
# because it is just a copy/hardlink of git.exe, rather than a unique binary.
2757+
$(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
2758+
$(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
2759+
$(INSTALL) git-upload-pack.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
2760+
$(INSTALL) git-credential-store.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2761+
$(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2762+
$(INSTALL) git-fast-import.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2763+
$(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2764+
$(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2765+
$(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2766+
$(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2767+
$(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2768+
$(INSTALL) git-remote-testsvn.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2769+
$(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2770+
$(INSTALL) git-show-index.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
2771+
ifndef DEBUG
2772+
$(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
2773+
$(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
2774+
else
2775+
$(INSTALL) $(vcpkg_dbg_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
2776+
$(INSTALL) $(vcpkg_dbg_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
2777+
endif
2778+
endif
27522779
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
27532780
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
27542781
$(INSTALL) -m 644 mergetools/* '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
@@ -2949,6 +2976,19 @@ endif
29492976
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
29502977
$(RM) GIT-USER-AGENT GIT-PREFIX
29512978
$(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
2979+
ifdef MSVC
2980+
$(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
2981+
$(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
2982+
$(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
2983+
$(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
2984+
$(RM) $(patsubst %.exe,%.pdb,$(PROGRAMS))
2985+
$(RM) $(patsubst %.exe,%.iobj,$(PROGRAMS))
2986+
$(RM) $(patsubst %.exe,%.ipdb,$(PROGRAMS))
2987+
$(RM) $(patsubst %.exe,%.pdb,$(TEST_PROGRAMS))
2988+
$(RM) $(patsubst %.exe,%.iobj,$(TEST_PROGRAMS))
2989+
$(RM) $(patsubst %.exe,%.ipdb,$(TEST_PROGRAMS))
2990+
$(RM) compat/vcbuild/MSVC-DEFS-GEN
2991+
endif
29522992

29532993
.PHONY: all install profile-clean cocciclean clean strip
29542994
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell

compat/mingw.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,6 +2415,12 @@ static void maybe_redirect_std_handles(void)
24152415
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
24162416
}
24172417

2418+
#ifdef _MSC_VER
2419+
#ifdef _DEBUG
2420+
#include <crtdbg.h>
2421+
#endif
2422+
#endif
2423+
24182424
/*
24192425
* We implement wmain() and compile with -municode, which would
24202426
* normally ignore main(), but we call the latter from the former
@@ -2430,6 +2436,12 @@ int wmain(int argc, const wchar_t **wargv)
24302436
char *buffer, **save;
24312437
const char **argv;
24322438

2439+
#ifdef _MSC_VER
2440+
#ifdef USE_MSVC_CRTDBG
2441+
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
2442+
#endif
2443+
#endif
2444+
24332445
maybe_redirect_std_handles();
24342446

24352447
/* determine size of argv and environ conversion buffer */

compat/vcbuild/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vcpkg/
2+
/MSVC-DEFS-GEN
3+
/VCPKG-DEFS

compat/vcbuild/README

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,54 @@
1+
The Steps to Build Git with VS2015 or VS2017 from the command line.
2+
3+
1. Install the "vcpkg" open source package manager and build essential
4+
third-party libraries. The steps for this have been captured in a
5+
set of convenience scripts. These can be run from a stock Command
6+
Prompt or from an SDK bash window:
7+
8+
$ cd <repo_root>
9+
$ ./compat/vcbuild/vcpkg_install.bat
10+
11+
The vcpkg tools and all of the third-party sources will be installed
12+
in this folder:
13+
<repo_root>/compat/vcbuild/vcpkg/
14+
15+
A file will be created with a set of Makefile macros pointing to a
16+
unified "include", "lib", and "bin" directory (release and debug) for
17+
all of the required packages. This file will be included by the main
18+
Makefile:
19+
<repo_root>/compat/vcbuild/MSVC-DEFS-GEN
20+
21+
2. OPTIONALLY copy the third-party *.dll and *.pdb files into the repo
22+
root to make it easier to run and debug git.exe without having to
23+
manipulate your PATH. This is especially true for debug sessions in
24+
Visual Studio.
25+
26+
Use ONE of the following forms which should match how you want to
27+
compile git.exe.
28+
29+
$ ./compat/vcbuild/vcpkg_copy_packages.bat debug
30+
$ ./compat/vcbuild/vcpkg_copy_packages.bat release
31+
32+
3. Build git using MSVC from an SDK bash window using one of the
33+
following commands:
34+
35+
$ make MSVC=1
36+
$ make MSVC=1 DEBUG=1
37+
38+
================================================================
39+
40+
Alternatively, run `make MSVC=1 vcxproj` and then load the generated
41+
git.sln in Visual Studio. The initial build will install the vcpkg
42+
system and build the dependencies automatically. This will take a while.
43+
44+
Note that this will automatically add and commit the generated
45+
.sln and .vcxproj files to the repo. You may want to drop this
46+
commit before submitting a Pull Request....
47+
48+
Or maybe we should put the .sln/.vcxproj files in the .gitignore file
49+
and not do this. I'm not sure.
50+
51+
================================================================
152
The Steps of Build Git with VS2008
253

354
1. You need the build environment, which contains the Git dependencies

compat/vcbuild/find_vs_env.bat

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
@ECHO OFF
2+
REM ================================================================
3+
REM You can use either GCC (the default) or MSVC to build git
4+
REM using the GIT-SDK command line tools.
5+
REM $ make
6+
REM $ make MSVC=1
7+
REM
8+
REM GIT-SDK BASH windows inherit environment variables with all of
9+
REM the bin/lib/include paths for GCC. It DOES NOT inherit values
10+
REM for the corresponding MSVC tools.
11+
REM
12+
REM During normal (non-git) Windows development, you launch one
13+
REM of the provided "developer command prompts" to set environment
14+
REM variables for the MSVC tools.
15+
REM
16+
REM Therefore, to allow MSVC command line builds of git from BASH
17+
REM and MAKE, we must blend these two different worlds. This script
18+
REM attempts to do that.
19+
REM ================================================================
20+
REM This BAT file starts in a plain (non-developer) command prompt,
21+
REM searches for the "best" commmand prompt setup script, installs
22+
REM it into the current CMD process, and exports the various MSVC
23+
REM environment variables for use by MAKE.
24+
REM
25+
REM The output of this script should be written to a make "include
26+
REM file" and referenced by the top-level Makefile.
27+
REM
28+
REM See "config.mak.uname" (look for compat/vcbuild/MSVC-DEFS-GEN).
29+
REM ================================================================
30+
REM The provided command prompts are custom to each VS release and
31+
REM filled with lots of internal knowledge (such as Registry settings);
32+
REM even their names vary by release, so it is not appropriate for us
33+
REM to look inside them. Rather, just run them in a subordinate
34+
REM process and extract the settings we need.
35+
REM ================================================================
36+
REM
37+
REM Current (VS2017 and beyond)
38+
REM -------------------
39+
REM Visual Studio 2017 introduced a new installation layout and
40+
REM support for side-by-side installation of multiple versions of
41+
REM VS2017. Furthermore, these can all coexist with installations
42+
REM of previous versions of VS (which have a completely different
43+
REM layout on disk).
44+
REM
45+
REM VS2017 Update 2 introduced a "vswhere.exe" command:
46+
REM https://github.com/Microsoft/vswhere
47+
REM https://blogs.msdn.microsoft.com/heaths/2017/02/25/vswhere-available/
48+
REM https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
49+
REM
50+
REM VS2015
51+
REM ------
52+
REM Visual Studio 2015 uses the traditional VcVarsAll.
53+
REM
54+
REM Earlier Versions
55+
REM ----------------
56+
REM TODO
57+
REM
58+
REM ================================================================
59+
REM Note: Throughout this script we use "dir <path> && <cmd>" rather
60+
REM than "if exist <path>" because of script problems with pathnames
61+
REM containing spaces.
62+
REM ================================================================
63+
64+
REM Sanitize PATH to prevent git-sdk paths from confusing "wmic.exe"
65+
REM (called internally in some of the system BAT files).
66+
SET PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;
67+
68+
REM ================================================================
69+
70+
:current
71+
SET vs_where=C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe
72+
dir "%vs_where%" >nul 2>nul && GOTO have_vs_where
73+
GOTO not_2017
74+
75+
:have_vs_where
76+
REM Try to use VsWhere to get the location of VsDevCmd.
77+
78+
REM Keep VsDevCmd from cd'ing away.
79+
SET VSCMD_START_DIR=.
80+
81+
REM Get the root of the VS product installation.
82+
FOR /F "usebackq tokens=*" %%i IN (`"%vs_where%" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath`) DO @SET vs_ip=%%i
83+
84+
SET vs_devcmd=%vs_ip%\Common7\Tools\VsDevCmd.bat
85+
dir "%vs_devcmd%" >nul 2>nul && GOTO have_vs_devcmd
86+
GOTO not_2017
87+
88+
:have_vs_devcmd
89+
REM Use VsDevCmd to setup the environment of this process.
90+
REM Setup CL for building 64-bit apps using 64-bit tools.
91+
@call "%vs_devcmd%" -no_logo -arch=x64 -host_arch=x64
92+
93+
SET tgt=%VSCMD_ARG_TGT_ARCH%
94+
95+
SET mn=%VCToolsInstallDir%
96+
SET msvc_includes=-I"%mn%INCLUDE"
97+
SET msvc_libs=-L"%mn%lib\%tgt%"
98+
SET msvc_bin_dir=%mn%bin\Host%VSCMD_ARG_HOST_ARCH%\%tgt%
99+
100+
SET sdk_dir=%WindowsSdkDir%
101+
SET sdk_ver=%WindowsSDKVersion%
102+
SET si=%sdk_dir%Include\%sdk_ver%
103+
SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared"
104+
SET sl=%sdk_dir%lib\%sdk_ver%
105+
SET sdk_libs=-L"%sl%ucrt\%tgt%" -L"%sl%um\%tgt%"
106+
107+
SET vs_ver=%VisualStudioVersion%
108+
109+
GOTO print_vars
110+
111+
REM ================================================================
112+
113+
:not_2017
114+
REM See if VS2015 is installed.
115+
116+
SET vs_2015_bat=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
117+
dir "%vs_2015_bat%" >nul 2>nul && GOTO have_vs_2015
118+
GOTO not_2015
119+
120+
:have_vs_2015
121+
REM Use VcVarsAll like the "x64 Native" command prompt.
122+
REM Setup CL for building 64-bit apps using 64-bit tools.
123+
@call "%vs_2015_bat%" amd64
124+
125+
REM Note that in VS2015 they use "x64" in some contexts and "amd64" in others.
126+
SET mn=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
127+
SET msvc_includes=-I"%mn%INCLUDE"
128+
SET msvc_libs=-L"%mn%lib\amd64"
129+
SET msvc_bin_dir=%mn%bin\amd64
130+
131+
SET sdk_dir=%WindowsSdkDir%
132+
SET sdk_ver=%WindowsSDKVersion%
133+
SET si=%sdk_dir%Include\%sdk_ver%
134+
SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared" -I"%si%winrt"
135+
SET sl=%sdk_dir%lib\%sdk_ver%
136+
SET sdk_libs=-L"%sl%ucrt\x64" -L"%sl%um\x64"
137+
138+
SET vs_ver=%VisualStudioVersion%
139+
140+
GOTO print_vars
141+
142+
REM ================================================================
143+
144+
:not_2015
145+
REM TODO....
146+
echo TODO support older versions of VS. >&2
147+
EXIT /B 1
148+
149+
REM ================================================================
150+
151+
:print_vars
152+
REM Dump the essential vars to stdout to allow the main
153+
REM Makefile to include it. See config.mak.uname.
154+
REM Include DOS-style and BASH-style path for bin dir.
155+
156+
echo msvc_bin_dir=%msvc_bin_dir%
157+
SET X1=%msvc_bin_dir:C:=/C%
158+
SET X2=%X1:\=/%
159+
echo msvc_bin_dir_msys=%X2%
160+
161+
echo msvc_includes=%msvc_includes%
162+
echo msvc_libs=%msvc_libs%
163+
164+
echo sdk_includes=%sdk_includes%
165+
echo sdk_libs=%sdk_libs%
166+
167+
echo vs_ver=%vs_ver%
168+
169+
EXIT /B 0

compat/vcbuild/scripts/clink.pl

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,61 @@
1212
use strict;
1313
my @args = ();
1414
my @cflags = ();
15+
my @lflags = ();
1516
my $is_linking = 0;
17+
my $is_debug = 0;
1618
while (@ARGV) {
1719
my $arg = shift @ARGV;
18-
if ("$arg" =~ /^-[DIMGO]/) {
20+
if ("$arg" eq "-DDEBUG") {
21+
# Some vcpkg-based libraries have different names for release
22+
# and debug versions. This hack assumes that -DDEBUG comes
23+
# before any "-l*" flags.
24+
$is_debug = 1;
25+
}
26+
if ("$arg" =~ /^-[DIMGOZ]/) {
1927
push(@cflags, $arg);
2028
} elsif ("$arg" eq "-o") {
2129
my $file_out = shift @ARGV;
2230
if ("$file_out" =~ /exe$/) {
2331
$is_linking = 1;
32+
# Create foo.exe and foo.pdb
2433
push(@args, "-OUT:$file_out");
2534
} else {
35+
# Create foo.o and foo.o.pdb
2636
push(@args, "-Fo$file_out");
37+
push(@args, "-Fd$file_out.pdb");
2738
}
2839
} elsif ("$arg" eq "-lz") {
40+
if ($is_debug) {
41+
push(@args, "zlibd.lib");
42+
} else{
2943
push(@args, "zlib.lib");
44+
}
3045
} elsif ("$arg" eq "-liconv") {
31-
push(@args, "iconv.lib");
46+
push(@args, "libiconv.lib");
3247
} elsif ("$arg" eq "-lcrypto") {
3348
push(@args, "libeay32.lib");
3449
} elsif ("$arg" eq "-lssl") {
3550
push(@args, "ssleay32.lib");
3651
} elsif ("$arg" eq "-lcurl") {
3752
push(@args, "libcurl.lib");
53+
} elsif ("$arg" eq "-lexpat") {
54+
push(@args, "expat.lib");
3855
} elsif ("$arg" =~ /^-L/ && "$arg" ne "-LTCG") {
3956
$arg =~ s/^-L/-LIBPATH:/;
40-
push(@args, $arg);
57+
push(@lflags, $arg);
4158
} elsif ("$arg" =~ /^-R/) {
4259
# eat
4360
} else {
4461
push(@args, $arg);
4562
}
4663
}
4764
if ($is_linking) {
65+
push(@args, @lflags);
4866
unshift(@args, "link.exe");
4967
} else {
5068
unshift(@args, "cl.exe");
5169
push(@args, @cflags);
5270
}
53-
#printf("**** @args\n");
71+
printf(STDERR "**** @args\n\n\n") if (!defined($ENV{'QUIET_GEN'}));
5472
exit (system(@args) != 0);

0 commit comments

Comments
 (0)