|
| 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; |
0 commit comments