package VC8WorkspaceCreator; # ************************************************************ # Description : A VC8 Workspace Creator # Author : Johnny Willemsen # Create Date : 4/21/2004 # ************************************************************ # ************************************************************ # Pragmas # ************************************************************ use strict; use VC8ProjectCreator; use VC71WorkspaceCreator; use vars qw(@ISA); @ISA = qw(VC71WorkspaceCreator); # ************************************************************ # Data Section # ************************************************************ ## NOTE: We call the constant as a function to support Perl 5.6. my %lang_map = (Creator::cplusplus() => 'Visual C#', Creator::csharp() => 'Visual C#', Creator::vb() => 'Visual Basic', Creator::java() => 'Visual J#'); # ************************************************************ # Subroutine Section # ************************************************************ sub pre_workspace { my($self, $fh) = @_; my $crlf = $self->crlf(); ## This identifies it as a Visual Studio 2005 file print $fh '', $crlf, 'Microsoft Visual Studio Solution File, Format Version 9.00', $crlf; ## Optionally print the workspace comment $self->print_workspace_comment($fh, '# Visual Studio 2005', $crlf, '# ', $crlf, '#', $crlf, '# This file was generated by MPC. Any changes made directly to', $crlf, '# this file will be lost the next time it is generated.', $crlf, '#', $crlf, '# MPC Command:', $crlf, '# ', $self->create_command_line_string($0, @ARGV), $crlf); } sub post_workspace { my($self, $fh, $creator) = @_; my $pjs = $self->get_project_info(); my @projects = $self->sort_dependencies($self->get_projects(), 0); my %gmap; ## Store a map of the project name to project guid and whether or not ## it is suitable to be referenced. Adding a reference to a ## non-managed c++ library or a "utility" project causes a warning in ## Visual Studio 2008 and higher. foreach my $project (@projects) { my($name, $guid, $lang, $custom_only, $managed) = $creator->access_pi_values($pjs, $project, ProjectCreator::PROJECT_NAME, ProjectCreator::PROJECT_GUID, ProjectCreator::LANGUAGE, ProjectCreator::CUSTOM_ONLY, ProjectCreator::MANAGED_PROJECT); $gmap{$name} = [$guid, !$custom_only && ($managed || $lang ne Creator::cplusplus)]; } ## Now go through the projects and check for the need to add external ## references. foreach my $project (@projects) { my $ph = new FileHandle(); my $outdir = $self->get_outdir(); my $cwd = $self->getcwd(); $outdir = $cwd if ($outdir eq '.'); my $full = $self->path_is_relative($project) ? "$outdir/$project" : $project; if (open($ph, $full)) { my $write; my @read; my $crlf = $self->crlf(); my $lang = $$pjs{$project}->[ProjectCreator::LANGUAGE]; my $managed = $$pjs{$project}->[ProjectCreator::MANAGED_PROJECT]; while(<$ph>) { ## This is a comment found in vc8.mpd if the project contains the ## 'after' keyword setting and the 'add_references' template ## variable setting. if (/^(\s*)get_validated_ordering($project); foreach my $dep (@$deps) { my $relative = $self->get_relative_dep_file($creator, $full, $dep); if (defined $relative) { $relative =~ s!/!\\!g; if ($lang eq Creator::cplusplus) { ## If the current project is not managed, then we will ## add references (although I doubt that will be useful). ## If the current project is managed, then the reference ## project must be managed or a non-c++ project. if (!$managed || ($managed && $gmap{$dep}->[1])) { ## See if the dependency has an associated attribute. ## If it does, split it into name value pairs for use in ## the resulting generated XML. my %attr; my $attr = $creator->get_dependency_attribute($dep); if (defined $attr) { foreach my $a (split(',', $attr)) { my @nvp = split('=', $a); $attr{lc($nvp[0])} = $nvp[1] if (defined $nvp[0] && defined $nvp[1]); } } push(@read, $self->cpp_proj_ref($spc, $gmap{$dep}->[0], \%attr, $relative)); } } ## This is a non-c++ language. So, it should not reference ## unmanaged c++ libraries. If it's a managed project or ## it's not a c++ project, it's ok to add a reference. elsif ($gmap{$dep}->[1]) { ## There are situations where, in C#, we want a dependency ## between projects but not want them linked together (via a ## ProjectReference). There is a build dependency, i.e., ## this project needs to be built if some other project is ## built. But, that's where the dependency ends. Setting ## the ProjectReference attribute to false allows us to do ## that. my $attr = $creator->get_dependency_attribute($dep); if (!defined $attr || $attr !~ /ProjectReference=false/i) { push(@read, $spc . '' . $crlf, $spc . ' {' . $gmap{$dep}->[0] . '}' . $crlf, $spc . ' ' . $dep . '' . $crlf, $spc . '' . $crlf); } } ## Indicate that we need to re-write the file $write = 1; } } last if (!$write); } else { push(@read, $_); } } close($ph); ## If we need to re-write the file, then do so if ($write && open($ph, ">$full")) { foreach my $line (@read) { print $ph $line; } close($ph); } } } } sub cpp_proj_ref { my ($self, $spc, $refguid, $attr, $relative) = @_; my $crlf = $self->crlf(); return $spc . '' . $crlf; } sub adjust_names { my($self, $name, $proj, $lang) = @_; ## For websites, the project needs to be the directory of the actual ## project file with a trailing slash. The name needs a trailing slash ## too. if ($lang eq Creator::website) { $proj = $self->mpc_dirname($proj); $proj .= '\\'; $name .= '\\' if $self->website_trailing_slash(); } ## This always needs to be a path with the Windows style directory ## separator. $proj =~ s/\//\\/g; return $name, $proj; } sub website_trailing_slash { return 1; } sub website_extra_props { } sub get_short_config_name { #my($self, $cfg) = @_; return $_[1]; } sub get_solution_config_section_name { #my $self = shift; return 'SolutionConfigurationPlatforms'; } sub get_project_config_section_name { #my $self = shift; return 'ProjectConfigurationPlatforms'; } sub print_additional_sections { my($self, $fh) = @_; my $crlf = $self->crlf(); print $fh "\tGlobalSection(SolutionProperties) = preSolution$crlf", "\t\tHideSolutionNode = FALSE$crlf", "\tEndGlobalSection$crlf"; } sub allow_empty_dependencies { #my $self = shift; return 0; } sub print_inner_project { my($self, $fh, $gen, $currguid, $deps, $name, $name_to_guid_map, $proj_language, $cfgs) = @_; ## We need to perform a lot of work, but only for websites. if ($proj_language eq Creator::website) { my $crlf = $self->crlf(); my $directory = ($name eq '.\\' ? $self->get_workspace_name() . '\\' : $name); ## We need the directory name with no trailing back-slash for use ## below. my $notrail = $directory; $notrail =~ s/\\$//; # Print the website project. print $fh "\tProjectSection(WebsiteProperties) = preProject", $crlf; $self->website_extra_props($fh); ## Print out the references my $references; foreach my $dep (@$deps) { if (defined $$name_to_guid_map{$dep}) { $references = "\t\t" . 'ProjectReferences = "' if (!defined $references); $references .= "{$$name_to_guid_map{$dep}}|$dep;"; } } print $fh $references, '"', $crlf if (defined $references); ## And now the configurations my %cfg_seen; foreach my $config (@$cfgs) { $config =~ s/\|.*//; if (!$cfg_seen{$config}) { print $fh "\t\t$config.AspNetCompiler.VirtualPath = \"/$notrail\"", $crlf, "\t\t$config.AspNetCompiler.PhysicalPath = \"$directory\"", $crlf, "\t\t$config.AspNetCompiler.TargetPath = \"PrecompiledWeb\\$directory\"", $crlf, "\t\t$config.AspNetCompiler.Updateable = \"true\"", $crlf, "\t\t$config.AspNetCompiler.ForceOverwrite = \"true\"", $crlf, "\t\t$config.AspNetCompiler.FixedNames = \"true\"", $crlf, "\t\t$config.AspNetCompiler.Debug = \"", ($config =~ /debug/i ? 'True' : 'False'), "\"", $crlf; $cfg_seen{$config} = 1; } } print $fh "\t\tVWDPort = \"1573\"", $crlf, "\t\tDefaultWebSiteLanguage = \"", $lang_map{$self->get_language()}, "\"", $crlf, "\tEndProjectSection", $crlf; } else { # We can ignore this project and pass it to the # SUPER since it's not a website. $self->SUPER::print_inner_project($fh, $gen, $currguid, $deps, $name, $name_to_guid_map); } } 1;