Skip to content

Commit 384a61b

Browse files
dschogitster
authored andcommitted
contrib/buildsystems: add a backend for modern Visual Studio versions
Based on the previous patches in this patch series that fixed the generator for `.vcproj` files (which were used by Visual Studio prior to 2015 to define projects), this patch offers to generate project definitions for neweer versions of Visual Studio (which use `.vcxproj` files). To that end, this patch copy-edits the generator of the `.vcproj`. In addition, we now use the `vcpkg` system which allows us to build Git's dependencies (e.g. curl, libexpat) conveniently. The support scripts were introduced in the `jh/msvc` patch series, and with this patch we initialize the `vcpkg` conditionally, in the `libgit` project's `PreBuildEvent`. To allow for parallel building of the projects, we therefore put `libgit` at the bottom of the project hierarchy. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4553f9d commit 384a61b

File tree

1 file changed

+385
-0
lines changed

1 file changed

+385
-0
lines changed
Lines changed: 385 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
1+
package Generators::Vcxproj;
2+
require Exporter;
3+
4+
use strict;
5+
use vars qw($VERSION);
6+
use Digest::SHA qw(sha256_hex);
7+
8+
our $VERSION = '1.00';
9+
our(@ISA, @EXPORT, @EXPORT_OK, @AVAILABLE);
10+
@ISA = qw(Exporter);
11+
12+
BEGIN {
13+
push @EXPORT_OK, qw(generate);
14+
}
15+
16+
sub generate_guid ($) {
17+
my $hex = sha256_hex($_[0]);
18+
$hex =~ s/^(.{8})(.{4})(.{4})(.{4})(.{12}).*/{$1-$2-$3-$4-$5}/;
19+
$hex =~ tr/a-z/A-Z/;
20+
return $hex;
21+
}
22+
23+
sub generate {
24+
my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
25+
my @libs = @{$build_structure{"LIBS"}};
26+
foreach (@libs) {
27+
createProject($_, $git_dir, $out_dir, $rel_dir, \%build_structure, 1);
28+
}
29+
30+
my @apps = @{$build_structure{"APPS"}};
31+
foreach (@apps) {
32+
createProject($_, $git_dir, $out_dir, $rel_dir, \%build_structure, 0);
33+
}
34+
35+
createGlueProject($git_dir, $out_dir, $rel_dir, %build_structure);
36+
return 0;
37+
}
38+
39+
sub createProject {
40+
my ($name, $git_dir, $out_dir, $rel_dir, $build_structure, $static_library) = @_;
41+
my $label = $static_library ? "lib" : "app";
42+
my $prefix = $static_library ? "LIBS_" : "APPS_";
43+
my $config_type = $static_library ? "StaticLibrary" : "Application";
44+
print "Generate $name vcxproj $label project\n";
45+
my $cdup = $name;
46+
$cdup =~ s/[^\/]+/../g;
47+
$cdup =~ s/\//\\/g;
48+
$rel_dir = $rel_dir eq "." ? $cdup : "$cdup\\$rel_dir";
49+
$rel_dir =~ s/\//\\/g;
50+
51+
my $target = $name;
52+
if ($static_library) {
53+
$target =~ s/\.a//;
54+
} else {
55+
$target =~ s/\.exe//;
56+
}
57+
58+
my $uuid = generate_guid($name);
59+
$$build_structure{"$prefix${target}_GUID"} = $uuid;
60+
my $vcxproj = $target;
61+
$vcxproj =~ s/(.*\/)?(.*)/$&\/$2.vcxproj/;
62+
$vcxproj =~ s/([^\/]*)(\/lib)\/(lib.vcxproj)/$1$2\/$1_$3/;
63+
$$build_structure{"$prefix${target}_VCXPROJ"} = $vcxproj;
64+
65+
my @srcs = sort(map("$rel_dir\\$_", @{$$build_structure{"$prefix${name}_SOURCES"}}));
66+
my @sources;
67+
foreach (@srcs) {
68+
$_ =~ s/\//\\/g;
69+
push(@sources, $_);
70+
}
71+
my $defines = join(";", sort(@{$$build_structure{"$prefix${name}_DEFINES"}}));
72+
my $includes= join(";", sort(map { s/^-I//; s/\//\\/g; File::Spec->file_name_is_absolute($_) ? $_ : "$rel_dir\\$_" } @{$$build_structure{"$prefix${name}_INCLUDES"}}));
73+
my $cflags = join(" ", sort(map { s/^-[GLMOWZ].*//; s/.* .*/"$&"/; $_; } @{$$build_structure{"$prefix${name}_CFLAGS"}}));
74+
$cflags =~ s/</&lt;/g;
75+
$cflags =~ s/>/&gt;/g;
76+
77+
my $libs_release = "\n ";
78+
my $libs_debug = "\n ";
79+
if (!$static_library) {
80+
$libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}}));
81+
$libs_debug = $libs_release;
82+
$libs_debug =~ s/zlib\.lib/zlibd\.lib/;
83+
}
84+
85+
$defines =~ s/-D//g;
86+
$defines =~ s/</&lt;/g;
87+
$defines =~ s/>/&gt;/g;
88+
$defines =~ s/\'//g;
89+
90+
die "Could not create the directory $target for $label project!\n" unless (-d "$target" || mkdir "$target");
91+
92+
open F, ">$vcxproj" or die "Could not open $vcxproj for writing!\n";
93+
binmode F, ":crlf :utf8";
94+
print F chr(0xFEFF);
95+
print F << "EOM";
96+
<?xml version="1.0" encoding="utf-8"?>
97+
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
98+
<ItemGroup Label="ProjectConfigurations">
99+
<ProjectConfiguration Include="Debug|Win32">
100+
<Configuration>Debug</Configuration>
101+
<Platform>Win32</Platform>
102+
</ProjectConfiguration>
103+
<ProjectConfiguration Include="Release|Win32">
104+
<Configuration>Release</Configuration>
105+
<Platform>Win32</Platform>
106+
</ProjectConfiguration>
107+
<ProjectConfiguration Include="Debug|x64">
108+
<Configuration>Debug</Configuration>
109+
<Platform>x64</Platform>
110+
</ProjectConfiguration>
111+
<ProjectConfiguration Include="Release|x64">
112+
<Configuration>Release</Configuration>
113+
<Platform>x64</Platform>
114+
</ProjectConfiguration>
115+
</ItemGroup>
116+
<PropertyGroup Label="Globals">
117+
<ProjectGuid>$uuid</ProjectGuid>
118+
<Keyword>Win32Proj</Keyword>
119+
<VCPKGArch Condition="'\$(Platform)'=='Win32'">x86-windows</VCPKGArch>
120+
<VCPKGArch Condition="'\$(Platform)'!='Win32'">x64-windows</VCPKGArch>
121+
<VCPKGArchDirectory>$cdup\\compat\\vcbuild\\vcpkg\\installed\\\$(VCPKGArch)</VCPKGArchDirectory>
122+
<VCPKGBinDirectory Condition="'\(Configuration)'=='Debug'">\$(VCPKGArchDirectory)\\debug\\bin</VCPKGBinDirectory>
123+
<VCPKGLibDirectory Condition="'\(Configuration)'=='Debug'">\$(VCPKGArchDirectory)\\debug\\lib</VCPKGLibDirectory>
124+
<VCPKGBinDirectory Condition="'\(Configuration)'!='Debug'">\$(VCPKGArchDirectory)\\bin</VCPKGBinDirectory>
125+
<VCPKGLibDirectory Condition="'\(Configuration)'!='Debug'">\$(VCPKGArchDirectory)\\lib</VCPKGLibDirectory>
126+
<VCPKGIncludeDirectory>\$(VCPKGArchDirectory)\\include</VCPKGIncludeDirectory>
127+
<VCPKGLibs Condition="'\(Configuration)'=='Debug'">$libs_debug</VCPKGLibs>
128+
<VCPKGLibs Condition="'\(Configuration)'!='Debug'">$libs_release</VCPKGLibs>
129+
</PropertyGroup>
130+
<Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
131+
<PropertyGroup Condition="'\$(Configuration)'=='Debug'" Label="Configuration">
132+
<UseDebugLibraries>true</UseDebugLibraries>
133+
<LinkIncremental>true</LinkIncremental>
134+
</PropertyGroup>
135+
<PropertyGroup Condition="'\$(Configuration)'=='Release'" Label="Configuration">
136+
<UseDebugLibraries>false</UseDebugLibraries>
137+
<WholeProgramOptimization>true</WholeProgramOptimization>
138+
</PropertyGroup>
139+
<PropertyGroup>
140+
<ConfigurationType>$config_type</ConfigurationType>
141+
<PlatformToolset>v140</PlatformToolset>
142+
<!-- <CharacterSet>UTF-8</CharacterSet> -->
143+
<OutDir>..\\</OutDir>
144+
<!-- <IntDir>\$(ProjectDir)\$(Configuration)\\</IntDir> -->
145+
</PropertyGroup>
146+
<Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" />
147+
<ImportGroup Label="ExtensionSettings">
148+
</ImportGroup>
149+
<ImportGroup Label="Shared">
150+
</ImportGroup>
151+
<ImportGroup Label="PropertySheets">
152+
<Import Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" Label="LocalAppDataPlatform" />
153+
</ImportGroup>
154+
<PropertyGroup Label="UserMacros" />
155+
<PropertyGroup>
156+
<GenerateManifest>false</GenerateManifest>
157+
<EnableManagedIncrementalBuild>true</EnableManagedIncrementalBuild>
158+
</PropertyGroup>
159+
<ItemDefinitionGroup>
160+
<ClCompile>
161+
<AdditionalOptions>$cflags %(AdditionalOptions)</AdditionalOptions>
162+
<AdditionalIncludeDirectories>$cdup;$cdup\\compat;$cdup\\compat\\regex;$cdup\\compat\\win32;$cdup\\compat\\poll;$cdup\\compat\\vcbuild\\include;\$(VCPKGIncludeDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
163+
<EnableParallelCodeGeneration />
164+
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
165+
<PrecompiledHeader />
166+
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
167+
</ClCompile>
168+
<Lib>
169+
<SuppressStartupBanner>true</SuppressStartupBanner>
170+
</Lib>
171+
<Link>
172+
<AdditionalLibraryDirectories>\$(VCPKGLibDirectory);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
173+
<AdditionalDependencies>\$(VCPKGLibs);\$(AdditionalDependencies)</AdditionalDependencies>
174+
<AdditionalOptions>invalidcontinue.obj %(AdditionalOptions)</AdditionalOptions>
175+
<EntryPointSymbol>wmainCRTStartup</EntryPointSymbol>
176+
<ManifestFile>$cdup\\compat\\win32\\git.manifest</ManifestFile>
177+
<SubSystem>Console</SubSystem>
178+
</Link>
179+
EOM
180+
if ($target eq 'libgit') {
181+
print F << "EOM";
182+
<PreBuildEvent Condition="!Exists('$cdup\\compat\\vcbuild\\vcpkg\\installed\\\$(VCPKGArch)\\include\\openssl\\ssl.h')">
183+
<Message>Initialize VCPKG</Message>
184+
<Command>del "$cdup\\compat\\vcbuild\\vcpkg"</Command>
185+
<Command>call "$cdup\\compat\\vcbuild\\vcpkg_install.bat"</Command>
186+
</PreBuildEvent>
187+
EOM
188+
}
189+
print F << "EOM";
190+
</ItemDefinitionGroup>
191+
<ItemDefinitionGroup Condition="'\$(Platform)'=='Win32'">
192+
<Link>
193+
<TargetMachine>MachineX86</TargetMachine>
194+
</Link>
195+
</ItemDefinitionGroup>
196+
<ItemDefinitionGroup Condition="'\$(Configuration)'=='Debug'">
197+
<ClCompile>
198+
<Optimization>Disabled</Optimization>
199+
<PreprocessorDefinitions>WIN32;_DEBUG;$defines;%(PreprocessorDefinitions)</PreprocessorDefinitions>
200+
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
201+
</ClCompile>
202+
<Link>
203+
<GenerateDebugInformation>true</GenerateDebugInformation>
204+
</Link>
205+
</ItemDefinitionGroup>
206+
<ItemDefinitionGroup Condition="'\$(Configuration)'=='Release'">
207+
<ClCompile>
208+
<Optimization>MaxSpeed</Optimization>
209+
<IntrinsicFunctions>true</IntrinsicFunctions>
210+
<PreprocessorDefinitions>WIN32;NDEBUG;$defines;%(PreprocessorDefinitions)</PreprocessorDefinitions>
211+
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
212+
<FunctionLevelLinking>true</FunctionLevelLinking>
213+
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
214+
</ClCompile>
215+
<Link>
216+
<GenerateDebugInformation>true</GenerateDebugInformation>
217+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
218+
<OptimizeReferences>true</OptimizeReferences>
219+
</Link>
220+
</ItemDefinitionGroup>
221+
<ItemGroup>
222+
EOM
223+
foreach(@sources) {
224+
print F << "EOM";
225+
<ClCompile Include="$_" />
226+
EOM
227+
}
228+
print F << "EOM";
229+
</ItemGroup>
230+
EOM
231+
if (!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') {
232+
my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"};
233+
my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"};
234+
235+
print F << "EOM";
236+
<ItemGroup>
237+
<ProjectReference Include="$cdup\\libgit\\libgit.vcxproj">
238+
<Project>$uuid_libgit</Project>
239+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
240+
</ProjectReference>
241+
EOM
242+
if (!($name =~ 'xdiff')) {
243+
print F << "EOM";
244+
<ProjectReference Include="$cdup\\xdiff\\lib\\xdiff_lib.vcxproj">
245+
<Project>$uuid_xdiff_lib</Project>
246+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
247+
</ProjectReference>
248+
EOM
249+
}
250+
if ($name =~ /(test-(line-buffer|svn-fe)|^git-remote-testsvn)\.exe$/) {
251+
my $uuid_vcs_svn_lib = $$build_structure{"LIBS_vcs-svn/lib_GUID"};
252+
print F << "EOM";
253+
<ProjectReference Include="$cdup\\vcs-svn\\lib\\vcs-svn_lib.vcxproj">
254+
<Project>$uuid_vcs_svn_lib</Project>
255+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
256+
</ProjectReference>
257+
EOM
258+
}
259+
print F << "EOM";
260+
</ItemGroup>
261+
EOM
262+
}
263+
print F << "EOM";
264+
<Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" />
265+
EOM
266+
if (!$static_library) {
267+
print F << "EOM";
268+
<Target Name="${target}_AfterBuild" AfterTargets="AfterBuild">
269+
<ItemGroup>
270+
<DLLsAndPDBs Include="\$(VCPKGBinDirectory)\\*.dll;\$(VCPKGBinDirectory)\\*.pdb" />
271+
</ItemGroup>
272+
<Copy SourceFiles="@(DLLsAndPDBs)" DestinationFolder="\$(OutDir)" SkipUnchangedFiles="true" UseHardlinksIfPossible="true" />
273+
<MakeDir Directories="..\\templates\\blt\\branches" />
274+
</Target>
275+
EOM
276+
}
277+
print F << "EOM";
278+
</Project>
279+
EOM
280+
close F;
281+
}
282+
283+
sub createGlueProject {
284+
my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
285+
print "Generate solutions file\n";
286+
$rel_dir = "..\\$rel_dir";
287+
$rel_dir =~ s/\//\\/g;
288+
my $SLN_HEAD = "Microsoft Visual Studio Solution File, Format Version 11.00\n# Visual Studio 2010\n";
289+
my $SLN_PRE = "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = ";
290+
my $SLN_POST = "\nEndProject\n";
291+
292+
my @libs = @{$build_structure{"LIBS"}};
293+
my @tmp;
294+
foreach (@libs) {
295+
$_ =~ s/\.a//;
296+
push(@tmp, $_);
297+
}
298+
@libs = @tmp;
299+
300+
my @apps = @{$build_structure{"APPS"}};
301+
@tmp = ();
302+
foreach (@apps) {
303+
$_ =~ s/\.exe//;
304+
if ($_ eq "git" ) {
305+
unshift(@tmp, $_);
306+
} else {
307+
push(@tmp, $_);
308+
}
309+
}
310+
@apps = @tmp;
311+
312+
open F, ">git.sln" || die "Could not open git.sln for writing!\n";
313+
binmode F, ":crlf :utf8";
314+
print F chr(0xFEFF);
315+
print F "$SLN_HEAD";
316+
317+
foreach (@apps) {
318+
my $appname = $_;
319+
my $uuid = $build_structure{"APPS_${appname}_GUID"};
320+
print F "$SLN_PRE";
321+
my $vcxproj = $build_structure{"APPS_${appname}_VCXPROJ"};
322+
$vcxproj =~ s/\//\\/g;
323+
$appname =~ s/.*\///;
324+
print F "\"${appname}\", \"${vcxproj}\", \"${uuid}\"";
325+
print F "$SLN_POST";
326+
}
327+
foreach (@libs) {
328+
my $libname = $_;
329+
my $uuid = $build_structure{"LIBS_${libname}_GUID"};
330+
print F "$SLN_PRE";
331+
my $vcxproj = $build_structure{"LIBS_${libname}_VCXPROJ"};
332+
$vcxproj =~ s/\//\\/g;
333+
$libname =~ s/\//_/g;
334+
print F "\"${libname}\", \"${vcxproj}\", \"${uuid}\"";
335+
print F "$SLN_POST";
336+
}
337+
338+
print F << "EOM";
339+
Global
340+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
341+
Debug|x64 = Debug|x64
342+
Debug|x86 = Debug|x86
343+
Release|x64 = Release|x64
344+
Release|x86 = Release|x86
345+
EndGlobalSection
346+
EOM
347+
print F << "EOM";
348+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
349+
EOM
350+
foreach (@apps) {
351+
my $appname = $_;
352+
my $uuid = $build_structure{"APPS_${appname}_GUID"};
353+
print F "\t\t${uuid}.Debug|x64.ActiveCfg = Debug|x64\n";
354+
print F "\t\t${uuid}.Debug|x64.Build.0 = Debug|x64\n";
355+
print F "\t\t${uuid}.Debug|x86.ActiveCfg = Debug|Win32\n";
356+
print F "\t\t${uuid}.Debug|x86.Build.0 = Debug|Win32\n";
357+
print F "\t\t${uuid}.Release|x64.ActiveCfg = Release|x64\n";
358+
print F "\t\t${uuid}.Release|x64.Build.0 = Release|x64\n";
359+
print F "\t\t${uuid}.Release|x86.ActiveCfg = Release|Win32\n";
360+
print F "\t\t${uuid}.Release|x86.Build.0 = Release|Win32\n";
361+
}
362+
foreach (@libs) {
363+
my $libname = $_;
364+
my $uuid = $build_structure{"LIBS_${libname}_GUID"};
365+
print F "\t\t${uuid}.Debug|x64.ActiveCfg = Debug|x64\n";
366+
print F "\t\t${uuid}.Debug|x64.Build.0 = Debug|x64\n";
367+
print F "\t\t${uuid}.Debug|x86.ActiveCfg = Debug|Win32\n";
368+
print F "\t\t${uuid}.Debug|x86.Build.0 = Debug|Win32\n";
369+
print F "\t\t${uuid}.Release|x64.ActiveCfg = Release|x64\n";
370+
print F "\t\t${uuid}.Release|x64.Build.0 = Release|x64\n";
371+
print F "\t\t${uuid}.Release|x86.ActiveCfg = Release|Win32\n";
372+
print F "\t\t${uuid}.Release|x86.Build.0 = Release|Win32\n";
373+
}
374+
375+
print F << "EOM";
376+
EndGlobalSection
377+
GlobalSection(SolutionProperties) = preSolution
378+
HideSolutionNode = FALSE
379+
EndGlobalSection
380+
EndGlobal
381+
EOM
382+
close F;
383+
}
384+
385+
1;

0 commit comments

Comments
 (0)