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/</</g;
75
+ $cflags =~ s/>/>/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/</</g;
87
+ $defines =~ s/>/>/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;