Files
2025-09-29 00:52:08 +02:00

701 lines
17 KiB
Ruby
Executable File

require 'xml'
require 'pipeline/coding/projbuild/project'
require 'pipeline/coding/projbuild/generators/vsshared'
module Pipeline
module ProjBuild
class VS2008VSSlnExporter < VSProjShared
@@log = nil
def VS2008VSSlnExporter.log
@@log = Log.new( 'vs2008vsslnexporter' ) if @@log == nil
@@log
end
def initialize()
@log = VS2008VSSlnExporter.log
config = Pipeline::Config.instance
# @p4 = SCM::Perforce.new()
# @p4.port = config.sc_server
# @p4.client = config.sc_workspace
# @p4.user = config.sc_username
# @p4.connect()
end
def export(path, project)
path = VS2008Generator.get_solution_filename(path)
#add_in_p4(path) as of yet adding is not supported - but I think it should be eventually.
sln_guid = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
proj_build = ProjBuildData::instance()
File.open(path,"w+") { |file|
main_filename = VS2008Generator.get_project_filename(project.name)
#identifying character sequence for a 2008 sln
file.putc(0xef)
file.putc(0xbb)
file.putc(0xbf)
file.write("\n")
file.write("Microsoft Visual Studio Solution File, Format Version 10.00\n")
file.write("# Visual Studio 2008\n")
file.write("Project(\"#{sln_guid}\") = \"#{project.name}\", \"#{main_filename}\", \"#{project.guid}\"\n")
file.write("\tProjectSection(ProjectDependencies) = postProject\n")
dep_guids = ActiveSupport::OrderedHash.new()
project.dep_guids.each { |dep_guid|
dep_guids[dep_guid] = true
dep_project = proj_build.dependent_projects[dep_guid]
file.write("\t\t#{dep_project.guid} = #{dep_project.guid}\n")
}
file.write("\tEndProjectSection\n")
file.write("EndProject\n")
proj_build.dependent_projects.keys.each { |dep_guid|
next if dep_guid == project.guid
dep_project = proj_build.dependent_projects[dep_guid]
filename = OS::Path.combine(dep_project.path,dep_project.name)
filename = OS::Path.dos_format(VS2008Generator.get_project_filename(filename))
file.write("Project(\"#{sln_guid}\") = \"#{dep_project.name}\", \"#{filename}\", \"#{dep_project.guid}\"\n")
file.write("EndProject\n")
}
file.write("Global\n")
file.write("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n")
proj_build.sln_platforms.each { |sln_platform,targets|
targets.each { |sln_target,proj_cfg|
platform_out = VSProjShared.get_platform_string(sln_platform)
config = "#{sln_target}|#{platform_out}"
file.write("\t\t#{config} = #{config}\n")
}
}
file.write("\tEndGlobalSection\n")
file.write("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n")
proj_build.sln_platforms.each { |sln_platform,targets|
targets.each { |sln_target,proj_cfgs|
#First process the start up project.
proj_cfg = proj_cfgs[project.guid]
prj_cfg = VSUtility.create_config_name(proj_cfg.platform,proj_cfg.target)
sln_cfg = "#{sln_target}|#{VSProjShared.get_platform_string(sln_platform)}"
config_out = "#{project.guid}.#{sln_cfg}"
file.write("\t\t#{config_out}.ActiveCfg = #{prj_cfg}\n")
file.write("\t\t#{config_out}.Build.0 = #{prj_cfg}\n")
#Process its dependent projects.
proj_build.dependent_projects.keys.each { |guid|
next if proj_cfgs[guid] == nil
proj_cfg = proj_cfgs[guid]
prj_cfg = VSUtility.create_config_name(proj_cfg.platform,proj_cfg.target)
sln_cfg = "#{sln_target}|#{VSProjShared.get_platform_string(sln_platform)}"
config_out = "#{guid}.#{sln_cfg}"
file.write("\t\t#{config_out}.ActiveCfg = #{prj_cfg}\n")
if dep_guids[guid] or guid == project.guid then
file.write("\t\t#{config_out}.Build.0 = #{prj_cfg}\n")
end
}
}
}
file.write("\tEndGlobalSection\n")
file.write("\tGlobalSection(SolutionProperties) = preSolution\n")
file.write("\t\tHideSolutionNode = FALSE\n")
file.write("\tEndGlobalSection\n")
file.write("EndGlobal\n")
}
revert_unchanged(path)
true
end
end
class VS2008VSProjExporter < VSProjExporterShared
@@log = nil
def VS2008VSProjExporter.log
@@log = Log.new( 'vs2008vsprojexporter' ) if @@log == nil
@@log
end
def initialize()
@log = VS2008VSProjExporter.log
@version = "2008"
end
protected
def create_project_node( project )
xml_node = XML::Node.new("VisualStudioProject")
xml_node.attributes["ProjectType"] = "Visual C++"
xml_node.attributes["Version"] = "9.00"
xml_node.attributes["Name"] = project.name
xml_node.attributes["ProjectGUID"] = project.guid
xml_node.attributes["Keyword"] = "Win32Proj"
xml_node.attributes["TargetFrameworkVersion"] = "131072"
xml_node
end
end
class VS2008VSProjLoader < VSProjShared
@@log = nil
def VS2008VSProjLoader.log
@@log = Log.new( 'vs2008vsprojloader' ) if @@log == nil
@@log
end
def initialize()
@log = VS2008VSProjLoader.log
end
def import( path, project_path = nil )
if File.exists?(path) == false then
@log.debug("couldn't open #{path}")
return false
end
@log.debug("checking #{path} with vs2008 project loader")
data = nil
parser = XML::Parser.file(path)
doc = parser.parse
if doc.root.attributes["Version"] != "9.00" then
@log.debug("#{path} not in the correct format")
return false
end
strip_unused_info(doc)
@log.debug("parsing #{path} with vs2008 project loader")
@curr_project = Info::Project.new(OS::Path.get_basename(path))
@curr_project.name = doc.root["Name"]
@curr_project_path = project_path if project_path != nil
@curr_project_path = OS::Path.normalise(OS::Path.get_directory(path)) unless project_path != nil
#files
files_node = doc.find_first("Files")
import_proj_files(files_node,@curr_project)
#root config
configs_node = doc.find_first("Configurations")
import_root_configs(configs_node)
@curr_project.guid = doc.root.attributes["ProjectGUID"]
@curr_project.config.xml_data = XML::Node.new("config")
@log.debug("parsed #{path}")
return true, @curr_project
end
protected
def strip_unused_info( doc )
doc.find("/VisualStudioProject/Configurations/Configuration/Tool").each { |xml_node|
case xml_node.attributes["Name"]
when "VCWebDeploymentTool":
xml_node.remove!
end
}
end
def import_file_config_hierarchy( xml_in )
xml_out = nil
if xml_in.name == "FileConfiguration" then
xml_out = XML::Node.new("config")
clone_attributes(xml_in,xml_out)
elsif xml_in.name == "Tool" then
xml_out = XML::Node.new(xml_in.attributes["Name"])
clone_attributes(xml_in,xml_out)
elsif xml_in.name == "custombuild" then
xml_out = XML::Node.new(xml_in.attributes["Name"])
clone_attributes(xml_in,xml_out)
end
# if xml_out == nil then
#
# ProjBuilder.log.debug("Not loaded!")
# ProjBuilder.log.debug(xml_in)
# end
if xml_out != nil and xml_in.children? then
xml_in.children.each { |child|
xml_new = import_file_config_hierarchy(child)
xml_out << xml_new if xml_new != nil
}
end
xml_out
end
def import_proj_files( xml_node, filter_node )
xml_node.find("File").each do |xml_file_node|
file_path = xml_file_node.attributes["RelativePath"]
file_path = File.expand_path(file_path,@curr_project_path)
new_file = Info::File.new(file_path)
xml_file_node.find("FileConfiguration").each do |xml_file_config_node|
platform, target = VSProjShared.parse_config_name(xml_file_config_node.attributes["Name"])
next if (platform == nil or target == nil)
config = new_file.platforms[platform].get_target(target)
config.xml_data = import_file_config_hierarchy(xml_file_config_node)
end
filter_node.files << new_file
end
xml_node.find("Filter").each do |xml_filter_node|
new_filter_node = Info::Filter.new(xml_filter_node.attributes["Name"])
filter_node.filters << new_filter_node
import_proj_files(xml_filter_node,new_filter_node)
end
end
def import_config_hierarchy( xml_in, doc, platform, target )
xml_out = nil
if xml_in.name == "Configuration" then
doc.root = XML::Node.new("config")
xml_out = XML::Node.new("vc")
doc.root << xml_out
case xml_in["ConfigurationType"]
when "1": doc.root["type"] = :exe.to_s
when "2": doc.root["type"] = :dll.to_s
when "4": doc.root["type"] = :library.to_s
end
doc.root["output_path"] = xml_in["OutputDirectory"].downcase if xml_in["OutputDirectory"]
elsif xml_in.name == "Tool" or xml_in.name == "custombuild"
found = false
if xml_in["Name"] == "VCCLCompilerTool" or xml_in["Name"] == "VCCLX360CompilerTool" then
if xml_in["AdditionalIncludeDirectories"] then
found = true
xml_incpaths = create_xml_path(doc.root,"includepaths")
dirs = xml_in["AdditionalIncludeDirectories"].split(";")
xml_in.attributes.get_attribute("AdditionalIncludeDirectories").remove!
dirs.each { |dir|
xml_incpath = XML::Node.new("includepath")
xml_incpath["path"] = dir
xml_incpaths << xml_incpath
}
end
if xml_in["PreprocessorDefinitions"] then
found = true
xml_defines = create_xml_path(doc.root,"defines")
defines = xml_in["PreprocessorDefinitions"].split(";")
xml_in.attributes.get_attribute("PreprocessorDefinitions").remove!
defines.each { |define|
next if define == ""
xml_define = XML::Node.new("define")
xml_define["value"] = define
xml_defines << xml_define
}
end
if xml_in["ForcedIncludeFiles"] then
found = true
xml_forceincludes = create_xml_path(doc.root,"forceincludes")
forceincludes = xml_in["ForcedIncludeFiles"].split(";")
xml_in.attributes.get_attribute("ForcedIncludeFiles").remove!
i = 0
forceincludes.each { |forceinclude|
xml_forceinclude = XML::Node.new("forceinclude")
xml_forceinclude["path"] = forceinclude
xml_forceinclude["order"] = i.to_s
i = i + 1
xml_forceincludes << xml_forceinclude
}
end
end
if (xml_in.attributes["Name"] != nil and xml_in.attributes.length > 1) then
xml_out = XML::Node.new(xml_in.attributes["Name"])
clone_attributes(xml_in,xml_out)
end
elsif xml_in.name == "DebuggerTool" then
xml_out = XML::Node.new("DebuggerTool")
clone_attributes(xml_in,xml_out)
end
# if xml_out == nil then
#
# ProjBuilder.log.debug("Not loaded!")
# ProjBuilder.log.debug(xml_in)
# end
if xml_out != nil and xml_in.children? then
xml_in.children.each { |child|
xml_new = import_config_hierarchy(child,doc,platform,target)
xml_out << xml_new if xml_new != nil
}
end
xml_out
end
def import_root_config( xml_node )
platform, target = VSProjShared.parse_config_name(xml_node.attributes["Name"])
return nil if ( platform.nil? or target.nil? )
config = @curr_project.platforms[platform].get_target(target)
doc = XML::Document.new()
import_config_hierarchy(xml_node,doc,platform,target)
config.xml_data = doc.root
end
def import_root_configs( xml_node )
config_nodes = xml_node.find("Configuration")
config_nodes.each do |xml_config_node|
import_root_config(xml_config_node)
end
end
end
class VS2008SlnLoader
attr_reader :projects
@@log = nil
def VS2008SlnLoader.log
@@log = Log.new( 'vs2008slnloader' ) if @@log == nil
@@log
end
def initialize()
@log = VS2008SlnLoader.log
end
def import( path )
@log.debug("parsing #{path}")
#make sure the path is absolute...
#set the parent path
@sln_dir = OS::Path.normalise(OS::Path.get_directory(path))
sln_lines = File.readlines(path)
# puts(sln_lines[0]) #first line is just a file format comment
state = :none
line_buffer = Array.new()
sln_lines.each { |line|
case state
when :none
if line.index("Project") == 0 then
state = :project
line_buffer = Array.new()
line_buffer << line
end
if line.index("Global") == 0 then
state = :global
line_buffer = Array.new()
line_buffer << line
end
when :project
if line.index("EndProject") == 0 then
state = :none
line_buffer << line
load_sln_project_section(line_buffer)
else
line_buffer << line
end
when :global
if line.index("EndGlobal") == 0 then
state = :none
line_buffer << line
load_sln_global_section(line_buffer)
else
line_buffer << line
end
end
}
return true, nil
end
def load_sln_project_section( lines )
tokens = lines[0].split("=")
tokens = tokens[1].split(",")
name = tokens[0]
proj_file = tokens[1].strip
proj_file = OS::Path.normalise(proj_file[1...(proj_file.size - 1)])
proj_file = File.expand_path(proj_file,@sln_dir)
guid = tokens[2]
deps = Array.new()
state = :none
lines.each { |line|
case state
when :none
if line.strip.index("ProjectSection(ProjectDependencies) = postProject") == 0 then
state = :deps
end
when :deps
if line.strip.index("EndProjectSection") == 0 then
state = :none
else
deps << line.split("=")[0].strip
end
end
}
loader = VS2008VSProjLoader.new()
ret, project = loader.import(proj_file)
ProjBuildData::instance().projects[project.guid] = project if ret == true
end
def load_sln_global_section( lines )
state = :none
lines.each { |line|
case state
when :none
if line.strip.index("GlobalSection(ProjectConfigurationPlatforms) = postSolution") == 0 then
state = :configs
end
when :configs
if line.strip.index("EndGlobalSection") == 0 then
state = :none
else
tokens = line.strip.split("=")
prj_data = tokens[0]
sln_cfg = tokens[1].strip
tokens = prj_data.split(".")
guid = tokens[0].strip
prj_cfg = tokens[1].strip
command = tokens[2].strip
if command == "ActiveCfg" then
sln_tokens = sln_cfg.split("|")
sln_platform = sln_tokens[1]
sln_target = sln_tokens[0]
proj_platform, proj_target = VSProjShared.parse_config_name(prj_cfg)
ProjBuildData::instance().add_projectconfig(sln_platform,sln_target,guid,proj_platform,proj_target)
end
end
end
}
end
end
class VS2008Generator
@@log = nil
def VS2008Generator.log
@@log = Log.new( 'VS2008Generator' ) if @@log == nil
@@log
end
def initialize()
@log = VS2008Generator.log
end
GENERATOR_ID = "2008"
@@unity_build_filenames = nil # if true filenames that are created have "_unity" in them.
def set_unity_build_filenames( set )
@@unity_build_filenames = set
end
def get_unity_build_filenames( )
@@unity_build_filenames
end
def self.get_project_filename( basename )
(@@unity_build_filenames and not basename.downcase.include?("shaders")) ? "#{basename}_#{GENERATOR_ID}_unity.vcproj" : "#{basename}_#{GENERATOR_ID}.vcproj"
end
def self.get_solution_filename( basename )
(@@unity_build_filenames and not basename.downcase.include?("shaders")) ? "#{basename}_#{GENERATOR_ID}_unity.sln" : "#{basename}_#{GENERATOR_ID}.sln"
end
def export( path, project, options = nil )
VS2008Generator.log.debug("exporting #{path} through vs2008 path")
if options != nil and options[:type] == :solution then
return VS2008VSSlnExporter.new().export(path,project)
else
path = VS2008Generator.get_project_filename(path)
return VS2008VSProjExporter.new().export(path,project)
end
false
end
def import( path, options = nil )
case OS::Path::get_extension(path).downcase
when 'sln':
@log.debug("import solution #{path}")
loader = VS2008SlnLoader.new()
return loader.import(path)
when 'vcproj':
@log.debug("import project #{path}")
loader = VS2008VSProjLoader.new()
return loader.import(path)
end
false
end
end
end #module ProjBuild
end #module Pipeline