Merge branch 'jt/send-email-validate-errors-fix'
[git] / contrib / buildsystems / Generators / Vcxproj.pm
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/g;
83       $libs_debug =~ s/libexpat\.lib/libexpatd\.lib/g;
84       $libs_debug =~ s/libcurl\.lib/libcurl-d\.lib/g;
85     }
86
87     $defines =~ s/-D//g;
88     $defines =~ s/</&lt;/g;
89     $defines =~ s/>/&gt;/g;
90     $defines =~ s/\'//g;
91
92     die "Could not create the directory $target for $label project!\n" unless (-d "$target" || mkdir "$target");
93
94     open F, ">$vcxproj" or die "Could not open $vcxproj for writing!\n";
95     binmode F, ":crlf :utf8";
96     print F chr(0xFEFF);
97     print F << "EOM";
98 <?xml version="1.0" encoding="utf-8"?>
99 <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
100   <ItemGroup Label="ProjectConfigurations">
101     <ProjectConfiguration Include="Debug|Win32">
102       <Configuration>Debug</Configuration>
103       <Platform>Win32</Platform>
104     </ProjectConfiguration>
105     <ProjectConfiguration Include="Release|Win32">
106       <Configuration>Release</Configuration>
107       <Platform>Win32</Platform>
108     </ProjectConfiguration>
109     <ProjectConfiguration Include="Debug|x64">
110       <Configuration>Debug</Configuration>
111       <Platform>x64</Platform>
112     </ProjectConfiguration>
113     <ProjectConfiguration Include="Release|x64">
114       <Configuration>Release</Configuration>
115       <Platform>x64</Platform>
116     </ProjectConfiguration>
117   </ItemGroup>
118   <PropertyGroup Label="Globals">
119     <ProjectGuid>$uuid</ProjectGuid>
120     <Keyword>Win32Proj</Keyword>
121     <VCPKGArch Condition="'\$(Platform)'=='Win32'">x86-windows</VCPKGArch>
122     <VCPKGArch Condition="'\$(Platform)'!='Win32'">x64-windows</VCPKGArch>
123     <VCPKGArchDirectory>$cdup\\compat\\vcbuild\\vcpkg\\installed\\\$(VCPKGArch)</VCPKGArchDirectory>
124     <VCPKGBinDirectory Condition="'\$(Configuration)'=='Debug'">\$(VCPKGArchDirectory)\\debug\\bin</VCPKGBinDirectory>
125     <VCPKGLibDirectory Condition="'\$(Configuration)'=='Debug'">\$(VCPKGArchDirectory)\\debug\\lib</VCPKGLibDirectory>
126     <VCPKGBinDirectory Condition="'\$(Configuration)'!='Debug'">\$(VCPKGArchDirectory)\\bin</VCPKGBinDirectory>
127     <VCPKGLibDirectory Condition="'\$(Configuration)'!='Debug'">\$(VCPKGArchDirectory)\\lib</VCPKGLibDirectory>
128     <VCPKGIncludeDirectory>\$(VCPKGArchDirectory)\\include</VCPKGIncludeDirectory>
129     <VCPKGLibs Condition="'\$(Configuration)'=='Debug'">$libs_debug</VCPKGLibs>
130     <VCPKGLibs Condition="'\$(Configuration)'!='Debug'">$libs_release</VCPKGLibs>
131   </PropertyGroup>
132   <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
133   <PropertyGroup Condition="'\$(Configuration)'=='Debug'" Label="Configuration">
134     <UseDebugLibraries>true</UseDebugLibraries>
135     <LinkIncremental>true</LinkIncremental>
136   </PropertyGroup>
137   <PropertyGroup Condition="'\$(Configuration)'=='Release'" Label="Configuration">
138     <UseDebugLibraries>false</UseDebugLibraries>
139     <WholeProgramOptimization>true</WholeProgramOptimization>
140   </PropertyGroup>
141   <PropertyGroup>
142     <ConfigurationType>$config_type</ConfigurationType>
143     <PlatformToolset>v140</PlatformToolset>
144     <!-- <CharacterSet>UTF-8</CharacterSet> -->
145     <OutDir>..\\</OutDir>
146     <!-- <IntDir>\$(ProjectDir)\$(Configuration)\\</IntDir> -->
147   </PropertyGroup>
148   <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" />
149   <ImportGroup Label="ExtensionSettings">
150   </ImportGroup>
151   <ImportGroup Label="Shared">
152   </ImportGroup>
153   <ImportGroup Label="PropertySheets">
154     <Import Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" Label="LocalAppDataPlatform" />
155   </ImportGroup>
156   <PropertyGroup Label="UserMacros" />
157   <PropertyGroup>
158     <GenerateManifest>false</GenerateManifest>
159     <EnableManagedIncrementalBuild>true</EnableManagedIncrementalBuild>
160   </PropertyGroup>
161   <ItemDefinitionGroup>
162     <ClCompile>
163       <AdditionalOptions>$cflags %(AdditionalOptions)</AdditionalOptions>
164       <AdditionalIncludeDirectories>$cdup;$cdup\\compat;$cdup\\compat\\regex;$cdup\\compat\\win32;$cdup\\compat\\poll;$cdup\\compat\\vcbuild\\include;\$(VCPKGIncludeDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
165       <EnableParallelCodeGeneration />
166       <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
167       <PrecompiledHeader />
168       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
169     </ClCompile>
170     <Lib>
171       <SuppressStartupBanner>true</SuppressStartupBanner>
172     </Lib>
173     <Link>
174       <AdditionalLibraryDirectories>\$(VCPKGLibDirectory);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
175       <AdditionalDependencies>\$(VCPKGLibs);\$(AdditionalDependencies)</AdditionalDependencies>
176       <AdditionalOptions>invalidcontinue.obj %(AdditionalOptions)</AdditionalOptions>
177       <EntryPointSymbol>wmainCRTStartup</EntryPointSymbol>
178       <ManifestFile>$cdup\\compat\\win32\\git.manifest</ManifestFile>
179       <SubSystem>Console</SubSystem>
180     </Link>
181 EOM
182     if ($target eq 'libgit') {
183         print F << "EOM";
184     <PreBuildEvent Condition="!Exists('$cdup\\compat\\vcbuild\\vcpkg\\installed\\\$(VCPKGArch)\\include\\openssl\\ssl.h')">
185       <Message>Initialize VCPKG</Message>
186       <Command>del "$cdup\\compat\\vcbuild\\vcpkg"</Command>
187       <Command>call "$cdup\\compat\\vcbuild\\vcpkg_install.bat"</Command>
188     </PreBuildEvent>
189 EOM
190     }
191     print F << "EOM";
192   </ItemDefinitionGroup>
193   <ItemDefinitionGroup Condition="'\$(Platform)'=='Win32'">
194     <Link>
195       <TargetMachine>MachineX86</TargetMachine>
196     </Link>
197   </ItemDefinitionGroup>
198   <ItemDefinitionGroup Condition="'\$(Configuration)'=='Debug'">
199     <ClCompile>
200       <Optimization>Disabled</Optimization>
201       <PreprocessorDefinitions>WIN32;_DEBUG;$defines;%(PreprocessorDefinitions)</PreprocessorDefinitions>
202       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
203     </ClCompile>
204     <Link>
205       <GenerateDebugInformation>true</GenerateDebugInformation>
206     </Link>
207   </ItemDefinitionGroup>
208   <ItemDefinitionGroup Condition="'\$(Configuration)'=='Release'">
209     <ClCompile>
210       <Optimization>MaxSpeed</Optimization>
211       <IntrinsicFunctions>true</IntrinsicFunctions>
212       <PreprocessorDefinitions>WIN32;NDEBUG;$defines;%(PreprocessorDefinitions)</PreprocessorDefinitions>
213       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
214       <FunctionLevelLinking>true</FunctionLevelLinking>
215       <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
216     </ClCompile>
217     <Link>
218       <GenerateDebugInformation>true</GenerateDebugInformation>
219       <EnableCOMDATFolding>true</EnableCOMDATFolding>
220       <OptimizeReferences>true</OptimizeReferences>
221     </Link>
222   </ItemDefinitionGroup>
223   <ItemGroup>
224 EOM
225     foreach(@sources) {
226         print F << "EOM";
227     <ClCompile Include="$_" />
228 EOM
229     }
230     print F << "EOM";
231   </ItemGroup>
232 EOM
233     if (!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') {
234       my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"};
235       my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"};
236
237       print F << "EOM";
238   <ItemGroup>
239     <ProjectReference Include="$cdup\\libgit\\libgit.vcxproj">
240       <Project>$uuid_libgit</Project>
241       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
242     </ProjectReference>
243 EOM
244       if (!($name =~ 'xdiff')) {
245         print F << "EOM";
246     <ProjectReference Include="$cdup\\xdiff\\lib\\xdiff_lib.vcxproj">
247       <Project>$uuid_xdiff_lib</Project>
248       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
249     </ProjectReference>
250 EOM
251       }
252       if ($name =~ /(test-(line-buffer|svn-fe)|^git-remote-testsvn)\.exe$/) {
253         my $uuid_vcs_svn_lib = $$build_structure{"LIBS_vcs-svn/lib_GUID"};
254         print F << "EOM";
255     <ProjectReference Include="$cdup\\vcs-svn\\lib\\vcs-svn_lib.vcxproj">
256       <Project>$uuid_vcs_svn_lib</Project>
257       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
258     </ProjectReference>
259 EOM
260       }
261       print F << "EOM";
262   </ItemGroup>
263 EOM
264     }
265     print F << "EOM";
266   <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" />
267 EOM
268     if (!$static_library) {
269       print F << "EOM";
270   <Target Name="${target}_AfterBuild" AfterTargets="AfterBuild">
271     <ItemGroup>
272       <DLLsAndPDBs Include="\$(VCPKGBinDirectory)\\*.dll;\$(VCPKGBinDirectory)\\*.pdb" />
273     </ItemGroup>
274     <Copy SourceFiles="@(DLLsAndPDBs)" DestinationFolder="\$(OutDir)" SkipUnchangedFiles="true" UseHardlinksIfPossible="true" />
275     <MakeDir Directories="..\\templates\\blt\\branches" />
276   </Target>
277 EOM
278     }
279     if ($target eq 'git') {
280       print F "  <Import Project=\"LinkOrCopyBuiltins.targets\" />\n";
281     }
282     if ($target eq 'git-remote-http') {
283       print F "  <Import Project=\"LinkOrCopyRemoteHttp.targets\" />\n";
284     }
285     print F << "EOM";
286 </Project>
287 EOM
288     close F;
289 }
290
291 sub createGlueProject {
292     my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
293     print "Generate solutions file\n";
294     $rel_dir = "..\\$rel_dir";
295     $rel_dir =~ s/\//\\/g;
296     my $SLN_HEAD = "Microsoft Visual Studio Solution File, Format Version 11.00\n# Visual Studio 2010\n";
297     my $SLN_PRE  = "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = ";
298     my $SLN_POST = "\nEndProject\n";
299
300     my @libs = @{$build_structure{"LIBS"}};
301     my @tmp;
302     foreach (@libs) {
303         $_ =~ s/\.a//;
304         push(@tmp, $_);
305     }
306     @libs = @tmp;
307
308     my @apps = @{$build_structure{"APPS"}};
309     @tmp = ();
310     foreach (@apps) {
311         $_ =~ s/\.exe//;
312         if ($_ eq "git" ) {
313             unshift(@tmp, $_);
314         } else {
315             push(@tmp, $_);
316         }
317     }
318     @apps = @tmp;
319
320     open F, ">git.sln" || die "Could not open git.sln for writing!\n";
321     binmode F, ":crlf :utf8";
322     print F chr(0xFEFF);
323     print F "$SLN_HEAD";
324
325     foreach (@apps) {
326         my $appname = $_;
327         my $uuid = $build_structure{"APPS_${appname}_GUID"};
328         print F "$SLN_PRE";
329         my $vcxproj = $build_structure{"APPS_${appname}_VCXPROJ"};
330         $vcxproj =~ s/\//\\/g;
331         $appname =~ s/.*\///;
332         print F "\"${appname}\", \"${vcxproj}\", \"${uuid}\"";
333         print F "$SLN_POST";
334     }
335     foreach (@libs) {
336         my $libname = $_;
337         my $uuid = $build_structure{"LIBS_${libname}_GUID"};
338         print F "$SLN_PRE";
339         my $vcxproj = $build_structure{"LIBS_${libname}_VCXPROJ"};
340         $vcxproj =~ s/\//\\/g;
341         $libname =~ s/\//_/g;
342         print F "\"${libname}\", \"${vcxproj}\", \"${uuid}\"";
343         print F "$SLN_POST";
344     }
345
346     print F << "EOM";
347 Global
348         GlobalSection(SolutionConfigurationPlatforms) = preSolution
349                 Debug|x64 = Debug|x64
350                 Debug|x86 = Debug|x86
351                 Release|x64 = Release|x64
352                 Release|x86 = Release|x86
353         EndGlobalSection
354 EOM
355     print F << "EOM";
356         GlobalSection(ProjectConfigurationPlatforms) = postSolution
357 EOM
358     foreach (@apps) {
359         my $appname = $_;
360         my $uuid = $build_structure{"APPS_${appname}_GUID"};
361         print F "\t\t${uuid}.Debug|x64.ActiveCfg = Debug|x64\n";
362         print F "\t\t${uuid}.Debug|x64.Build.0 = Debug|x64\n";
363         print F "\t\t${uuid}.Debug|x86.ActiveCfg = Debug|Win32\n";
364         print F "\t\t${uuid}.Debug|x86.Build.0 = Debug|Win32\n";
365         print F "\t\t${uuid}.Release|x64.ActiveCfg = Release|x64\n";
366         print F "\t\t${uuid}.Release|x64.Build.0 = Release|x64\n";
367         print F "\t\t${uuid}.Release|x86.ActiveCfg = Release|Win32\n";
368         print F "\t\t${uuid}.Release|x86.Build.0 = Release|Win32\n";
369     }
370     foreach (@libs) {
371         my $libname = $_;
372         my $uuid = $build_structure{"LIBS_${libname}_GUID"};
373         print F "\t\t${uuid}.Debug|x64.ActiveCfg = Debug|x64\n";
374         print F "\t\t${uuid}.Debug|x64.Build.0 = Debug|x64\n";
375         print F "\t\t${uuid}.Debug|x86.ActiveCfg = Debug|Win32\n";
376         print F "\t\t${uuid}.Debug|x86.Build.0 = Debug|Win32\n";
377         print F "\t\t${uuid}.Release|x64.ActiveCfg = Release|x64\n";
378         print F "\t\t${uuid}.Release|x64.Build.0 = Release|x64\n";
379         print F "\t\t${uuid}.Release|x86.ActiveCfg = Release|Win32\n";
380         print F "\t\t${uuid}.Release|x86.Build.0 = Release|Win32\n";
381     }
382
383     print F << "EOM";
384         EndGlobalSection
385         GlobalSection(SolutionProperties) = preSolution
386                 HideSolutionNode = FALSE
387         EndGlobalSection
388 EndGlobal
389 EOM
390     close F;
391 }
392
393 1;