Skip to content

Commit bffa7c2

Browse files
committed
contrib/buildsystems: add a backend for modern Visual Studio versions
Based on the previous patch series to be able to compile Git using Visual C++ from the command-line, this patch offers to generate project definitions for Visual Studio, so that Git can be developed in a modern IDE. Based on the generator for Visual Studio versions <= 2008 (which used .sln/.vcproj files), this patch copy-edits the generator of the .vcproj files to a new generator that produces .vcxproj files ready for Visual Studio 2010 and later (or MSBuild). As the vcpkg system (which is used to build Git's dependencies) cannot run in parallel (it does not lock, wreaking havoc with files being accessed and written at the same time, letting the vcpkg processes stumble over each others' toes), we make libgit the root of the project dependency tree and initialize the vcpkg system in this project's PreBuildEvent. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent b62de3e commit bffa7c2

File tree

2 files changed

+382
-0
lines changed

2 files changed

+382
-0
lines changed
Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
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+
<MinimalRebuild>true</MinimalRebuild>
165+
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
166+
<PrecompiledHeader />
167+
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
168+
</ClCompile>
169+
<Lib>
170+
<SuppressStartupBanner>true</SuppressStartupBanner>
171+
</Lib>
172+
<Link>
173+
<AdditionalLibraryDirectories>\$(VCPKGLibDirectory);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
174+
<AdditionalDependencies>\$(VCPKGLibs);\$(AdditionalDependencies)</AdditionalDependencies>
175+
<AdditionalOptions>invalidcontinue.obj %(AdditionalOptions)</AdditionalOptions>
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') {
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+
<ProjectReference Include="$cdup\\xdiff\\lib\\xdiff_lib.vcxproj">
242+
<Project>$uuid_xdiff_lib</Project>
243+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
244+
</ProjectReference>
245+
EOM
246+
if ($name =~ /(test-(line-buffer|svn-fe)|^git-remote-testsvn)\.exe$/) {
247+
my $uuid_vcs_svn_lib = $$build_structure{"LIBS_vcs-svn/lib_GUID"};
248+
print F << "EOM";
249+
<ProjectReference Include="$cdup\\vcs-svn\\lib\\vcs-svn_lib.vcxproj">
250+
<Project>$uuid_vcs_svn_lib</Project>
251+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
252+
</ProjectReference>
253+
EOM
254+
}
255+
print F << "EOM";
256+
</ItemGroup>
257+
EOM
258+
}
259+
print F << "EOM";
260+
<Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" />
261+
EOM
262+
if (!$static_library) {
263+
print F << "EOM";
264+
<Target Name="${target}_AfterBuild" AfterTargets="AfterBuild">
265+
<ItemGroup>
266+
<DLLsAndPDBs Include="\$(VCPKGBinDirectory)\\*.dll;\$(VCPKGBinDirectory)\\*.pdb" />
267+
</ItemGroup>
268+
<Copy SourceFiles="@(DLLsAndPDBs)" DestinationFolder="\$(OutDir)" SkipUnchangedFiles="true" UseHardlinksIfPossible="true" />
269+
</Target>
270+
EOM
271+
}
272+
print F << "EOM";
273+
</Project>
274+
EOM
275+
close F;
276+
}
277+
278+
sub createGlueProject {
279+
my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
280+
print "Generate solutions file\n";
281+
$rel_dir = "..\\$rel_dir";
282+
$rel_dir =~ s/\//\\/g;
283+
my $SLN_HEAD = "Microsoft Visual Studio Solution File, Format Version 11.00\n# Visual Studio 2010\n";
284+
my $SLN_PRE = "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = ";
285+
my $SLN_POST = "\nEndProject\n";
286+
287+
my @libs = @{$build_structure{"LIBS"}};
288+
my @tmp;
289+
foreach (@libs) {
290+
$_ =~ s/\.a//;
291+
push(@tmp, $_);
292+
}
293+
@libs = @tmp;
294+
295+
my @apps = @{$build_structure{"APPS"}};
296+
@tmp = ();
297+
foreach (@apps) {
298+
$_ =~ s/\.exe//;
299+
if ($_ eq "git" ) {
300+
unshift(@tmp, $_);
301+
} else {
302+
push(@tmp, $_);
303+
}
304+
}
305+
@apps = @tmp;
306+
307+
open F, ">git.sln" || die "Could not open git.sln for writing!\n";
308+
binmode F, ":crlf :utf8";
309+
print F chr(0xFEFF);
310+
print F "$SLN_HEAD";
311+
312+
foreach (@apps) {
313+
my $appname = $_;
314+
my $uuid = $build_structure{"APPS_${appname}_GUID"};
315+
print F "$SLN_PRE";
316+
my $vcxproj = $build_structure{"APPS_${appname}_VCXPROJ"};
317+
$vcxproj =~ s/\//\\/g;
318+
$appname =~ s/.*\///;
319+
print F "\"${appname}\", \"${vcxproj}\", \"${uuid}\"";
320+
print F "$SLN_POST";
321+
}
322+
foreach (@libs) {
323+
my $libname = $_;
324+
my $uuid = $build_structure{"LIBS_${libname}_GUID"};
325+
print F "$SLN_PRE";
326+
my $vcxproj = $build_structure{"LIBS_${libname}_VCXPROJ"};
327+
$vcxproj =~ s/\//\\/g;
328+
$libname =~ s/\//_/g;
329+
print F "\"${libname}\", \"${vcxproj}\", \"${uuid}\"";
330+
print F "$SLN_POST";
331+
}
332+
333+
print F << "EOM";
334+
Global
335+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
336+
Debug|x64 = Debug|x64
337+
Debug|x86 = Debug|x86
338+
Release|x64 = Release|x64
339+
Release|x86 = Release|x86
340+
EndGlobalSection
341+
EOM
342+
print F << "EOM";
343+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
344+
EOM
345+
foreach (@apps) {
346+
my $appname = $_;
347+
my $uuid = $build_structure{"APPS_${appname}_GUID"};
348+
print F "\t\t${uuid}.Debug|x64.ActiveCfg = Debug|x64\n";
349+
print F "\t\t${uuid}.Debug|x64.Build.0 = Debug|x64\n";
350+
print F "\t\t${uuid}.Debug|x86.ActiveCfg = Debug|Win32\n";
351+
print F "\t\t${uuid}.Debug|x86.Build.0 = Debug|Win32\n";
352+
print F "\t\t${uuid}.Release|x64.ActiveCfg = Release|x64\n";
353+
print F "\t\t${uuid}.Release|x64.Build.0 = Release|x64\n";
354+
print F "\t\t${uuid}.Release|x86.ActiveCfg = Release|Win32\n";
355+
print F "\t\t${uuid}.Release|x86.Build.0 = Release|Win32\n";
356+
}
357+
foreach (@libs) {
358+
my $libname = $_;
359+
my $uuid = $build_structure{"LIBS_${libname}_GUID"};
360+
print F "\t\t${uuid}.Debug|x64.ActiveCfg = Debug|x64\n";
361+
print F "\t\t${uuid}.Debug|x64.Build.0 = Debug|x64\n";
362+
print F "\t\t${uuid}.Debug|x86.ActiveCfg = Debug|Win32\n";
363+
print F "\t\t${uuid}.Debug|x86.Build.0 = Debug|Win32\n";
364+
print F "\t\t${uuid}.Release|x64.ActiveCfg = Release|x64\n";
365+
print F "\t\t${uuid}.Release|x64.Build.0 = Release|x64\n";
366+
print F "\t\t${uuid}.Release|x86.ActiveCfg = Release|Win32\n";
367+
print F "\t\t${uuid}.Release|x86.Build.0 = Release|Win32\n";
368+
}
369+
370+
print F << "EOM";
371+
EndGlobalSection
372+
GlobalSection(SolutionProperties) = preSolution
373+
HideSolutionNode = FALSE
374+
EndGlobalSection
375+
EndGlobal
376+
EOM
377+
close F;
378+
}
379+
380+
1;

contrib/buildsystems/engine.pl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ sub handleLinkLine
347347
push(@libs, "ssleay32.lib");
348348
} elsif ("$part" eq "-lcurl") {
349349
push(@libs, "libcurl.lib");
350+
} elsif ("$part" eq "-lexpat") {
351+
push(@libs, "expat.lib");
350352
} elsif ("$part" eq "-liconv") {
351353
push(@libs, "libiconv.lib");
352354
} elsif ($part =~ /^[-\/]/) {

0 commit comments

Comments
 (0)