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

1347 lines
45 KiB
Ruby
Executable File

require 'xml'
require 'active_support/ordered_hash'
require 'pipeline/coding/projbuild/project'
require 'pipeline/coding/xml2vsxml'
require 'pipeline/coding/projbuild/scriptutility'
require 'pipeline/coding/projbuild/generators/vsshared'
require 'pipeline/coding/projbuild/custom/custom_build_step'
require 'pipeline/os/file'
require 'pipeline/os/path'
module Pipeline
module ProjBuild
# DW - WTF is this shit?
#HACK: Global search paths to be shared across all RageGen2010SolutionLoaders created.
$search_guid_paths = Hash.new()
class RageGen2010SolutionLoader
@@log = nil
def RageGen2010SolutionLoader.log
@@log = Log.new( 'ragegen2010solutionloader' ) if @@log == nil
@@log
end
def initialize()
if $search_guid_paths == nil
$search_guid_paths = Hash.new()
end
end
def import( path, output_format, options )
RageGen2010SolutionLoader.log.info("Trying to import #{path} with ragegen project loader.")
selected_template = ScriptUtility.determine_solution_template(path)
if selected_template == nil
RageGen2010SolutionLoader.log.info("Template doesn't exist: #{selected_template}!")
return false
end
config_filename = "#{selected_template}.configs"
if File.exists?(config_filename) == false then
print "Config file does not exist: #{config_filename}\n"
RageGen2010SolutionLoader.log.info("template doesn't exist: #{config_filename}")
return false
end
solution_generation = ScriptUtility.acquire_variable(path, 'NO_SOLUTION_GENERATION')
if solution_generation != nil and solution_generation != ""
#Due to our reliance on the RageGen generation method to generate multiple projects
#in one folder, the ability to circumvent solution generation is inserted here.
print "No solution generation is switched on within #{path}. No solutions will be generated.\n"
return true
end
testers_var = ScriptUtility.acquire_variable(path, 'TESTERS')
testers_var = "" if testers_var.nil?
RageGen2010SolutionLoader.log.info("testers_var #{testers_var}")
archive = ScriptUtility.acquire_variable(path, 'ARCHIVE')
testers_var += " " + archive if archive.nil? == false
@tester_array = testers_var.split(" ")
@working_directory = File.dirname(path)
build_data = ProjBuildData::instance()
build_data.reset
success = true
projects = Array.new()
@tester_array.each do |tester|
RageGen2010SolutionLoader.log.info("running tester #{tester}")
basename = OS::Path.get_basename(tester)
solution_file = OS::Path::combine(@working_directory, basename)
print "Generating #{solution_file}...\n"
#Read the .config file for all configurations to add to the solution.
platforms = ActiveSupport::OrderedHash.new()
targets = ActiveSupport::OrderedHash.new()
File.readlines(config_filename).each { |line|
tokens = line.split("=")
sln = tokens[0]
proj = tokens[1]
sln_tokens = sln.split("|")
if sln_tokens.size == 1
line.strip!
print "Unable to parse line \"#{line}\" in #{config_filename}!\n"
next
end
sln_target = sln.split("|")[0].strip
sln_platform = VSProjShared.get_platform(sln.split("|")[1].strip)
if proj == nil then
proj = sln
end
if platforms[sln_platform] == nil then
platforms[sln_platform] = Hash.new()
end
platforms[sln_platform][sln_target] = proj
}
#load in the root project...
guid_filename = OS::Path::combine(@working_directory, basename) + ".guid"
guid = VSProjShared.create_guid(guid_filename, @p4)
project = Info::Project.new(basename)
project.guid = guid
project.path = Dir.getwd
platforms.keys.each { |sln_platform|
targets = platforms[sln_platform]
targets.keys.each { |sln_target|
proj_cfg = targets[sln_target]
proj_platform, proj_target = VSProjShared.parse_config_name(proj_cfg)
build_data.add_projectconfig(sln_platform,sln_target,project.guid,proj_platform,proj_target)
}
}
build_data.projects[project.guid] = project
build_data.root_guid = guid
#load in each of the dependent projects...
search_paths = Array.new()
xproj = ScriptUtility.acquire_variable(path, 'XPROJ')
if xproj != nil
xproj.split(' ').each { |xpath|
search_paths << xpath
}
end
self_search_path = File.dirname(path) + "/"
self_search_path = OS::Path.normalise(self_search_path)
search_paths << self_search_path
search_paths << "%RAGE_DIR%\\stlport\\STLport-5.0RC5\\"
search_paths << "%RAGE_DIR%\\base\\src\\"
search_paths << "%RAGE_DIR%\\suite\\src\\"
search_paths << "%RAGE_DIR%\\base\\samples\\"
search_paths << "%RAGE_DIR%\\suite\\samples\\"
search_paths << "%RAGE_DIR%\\base\\tools\\"
search_paths << "%RAGE_DIR%\\suite\\tools\\"
libs = ScriptUtility.acquire_expanded_libs(path, basename)
RageGen2010SolutionLoader.log.info("libs #{libs.length} #{libs}")
Dir.chdir(OS::Path.get_directory(path)) {
if libs != nil
libs.each { |lib|
lib_name = OS::Path.get_basename(lib)
lib = OS::Path.normalise(lib)
guid = nil
guid_filename = nil
if (lib.index(":") == nil) and (lib.index("/") == nil) then
found = false
ambiguous = false
base_guid_name = "#{lib_name}.guid"
search_paths.each { |search_path|
search_path = ScriptUtility.convert_paths_in_line(search_path)
if $search_guid_paths[base_guid_name] != nil
found = true
guid_filename = $search_guid_paths[base_guid_name]
break
else
search_path = File.join(search_path, "**", base_guid_name)
search_path.gsub!("\\", "/")
found_files = Dir.glob( search_path )
if found_files.size == 1
found = true
guid_filename = found_files[0]
$search_guid_paths[base_guid_name] = guid_filename
break
elsif found_files.size > 1
ambiguous = true
break
end
end
}
if found == false
if ambiguous == true
RageGen2010SolutionLoader.log.debug("Ambiguous project! Multiple objects found; unable to resolve without a more precise path for project: #{lib}!")
print "Multiple GUID files have been found with the same name #{lib}.guid. Unable to proceed!\n"
else
RageGen2010SolutionLoader.log.debug("Unable to find any file for the library: #{lib}!")
print "Unable to find the library GUID: #{lib}\n"
return
end
next
end
else
lib = OS::Path.remove_extension(lib)
lib = File.expand_path(lib)
guid_filename = "#{lib}.guid"
end
guid_filename = OS::Path::make_relative( guid_filename, @working_directory )
guid = VSProjShared.create_guid(guid_filename, @p4)
if guid == nil
RageGen2010SolutionLoader.log.debug("Unable to acquire guid #{guid_filename}!")
print "Unable to acquire guid #{guid_filename}!\n"
return
end
guid = guid.strip.upcase
child_project = Info::Project.new(lib_name)
child_project.guid = guid
child_project.path = OS::Path.get_directory(guid_filename)
search_guid = child_project.guid[1..-2]
ignore_guids = ENV['IGNORE_GUIDS']
ignore_guids = ScriptUtility.acquire_variable(path, 'IGNORE_GUIDS') if ignore_guids == nil
#Assume that the startup project is dependent on all child projects.
if ignore_guids == nil or ignore_guids.index(search_guid) == nil then
project.dep_guids << child_project.guid
end
platforms.keys.each { |sln_platform|
targets = platforms[sln_platform]
targets.each_pair { |sln_target,proj_cfg|
proj_platform, proj_target = VSProjShared.parse_config_name(proj_cfg)
build_data.add_projectconfig(sln_platform,sln_target,child_project.guid,proj_platform,proj_target)
}
}
RageGen2010SolutionLoader.log.info("#Adding dependent project #{child_project.guid} #{child_project}")
build_data.dependent_projects[child_project.guid] = child_project
}
end
}
projects << project
end
return true, projects
end
end
#===================================================================
#
#
#
class RageGen2010ProjectLoader < VSProjShared
@@log = nil
def RageGen2010ProjectLoader.log
@@log = Log.new( 'ragegen2010projectloader' ) if @@log == nil
@@log
end
def initialize()
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 find_files(path, extension, array)
#Handle any regular expressions
found_files = []
found_files = OS::FindEx::find_files_recurse( path + extension )
found_files.each do |found_file|
array.insert(array.size, found_file)
end
end
def process_qa_items(input_path)
input_dir = File.dirname(input_path)
found_files = OS::FindEx::find_files( OS::Path::combine(input_dir, "*.cpp") )
if found_files.size > 0
qaitems_header_path = OS::Path::combine(input_dir, "qaitems.h")
qaitems_source_path = OS::Path::combine(input_dir, "qaitems.cpp")
edit_in_p4(@p4, qaitems_header_path)
edit_in_p4(@p4, qaitems_source_path)
source_file_path = OS::Path::combine( input_dir, "*.cpp")
grep_exe = get_egrep_exe_path()
result = system(grep_exe + ' -h "^QA_ITEM" ' + source_file_path + ' > ' + qaitems_header_path)
if result == false
if File.exists?(qaitems_header_path)
File.delete(qaitems_header_path)
end
revert_from_p4(@p4, qaitems_header_path)
return
end
edit_in_p4(@p4, qaitems_header_path)
#QA Items have been found, so add qaitems as a tester to regenerate and add to source control.
@testers = @testers + " qaitems"
result = system( grep_exe + ' -s -h "^QA_ITEM_DRAW" ' + qaitems_header_path )
if result == false
if ENV["RAGE_DIR"] != nil
system('copy' + ENV["RAGE_DIR"] + '\qa\src\unittest\qaitemsdraw.cpp ' + qaitems_source_path)
end
edit_in_p4(@p4, qaitems_source_path)
return
end
@xdefine_var = @xdefine_var + " QA_ITEMS_DEPEND_ON_SAMPLE_GRCORE"
end
end
# DW - I seriously do not understand why this step is required - what does it achieve?
def create_project_definition_file( directory, project_name, guid, specified_files )
project_definition_file_name = OS::Path::combine(directory, "#{project_name}.rsp")
project_file = OS::Path::combine(directory, project_name)
if File.exist?(project_file + ".cpp")
project_file_source = project_file + ".cpp"
duplicate_file = false
specified_files.each do |file|
if project_file_source == file
duplicate_file = true
break
end
end
if duplicate_file == false
specified_files.insert(specified_files.size, project_file_source)
end
elsif File.exist?(project_file + ".c")
project_file_source = project_file + ".c"
duplicate_file = false
specified_files.each do |file|
if project_file_source == file
duplicate_file = true
break
end
end
if duplicate_file == false
specified_files.insert(specified_files.size, project_file_source)
end
end
#Add all extra files to the list.
# TODO: Re-evaluate if this is ever necessary.
if specified_files.size == 0
specified_files = []
specified_files = OS::FindEx::find_files( Pipeline::OS::Path::combine(directory, "*.h") ) #/.*[.]h|.*[.]cpp|(.*)[.]c/
specified_files += OS::FindEx::find_files( Pipeline::OS::Path::combine(directory, "*.cpp") )
specified_files += OS::FindEx::find_files( Pipeline::OS::Path::combine(directory, "*.c") )
end
file = File.new(project_definition_file_name, 'w')
#First line is always the project name
file.write(project_name + "\n")
#Second line is always the guid.
file.write(guid + "\n")
specified_files.each do |found_file|
file.write(found_file + "\n")
end
file.close
return project_definition_file_name
end
# DW - look here modularity!
# supports import method
def read_makefile(path)
#Makefile Variables
@testers = ScriptUtility.acquire_variable( path, 'TESTERS' )
@testers = "" if @testers.nil?
@xdefine_var = ScriptUtility.acquire_variable(path, 'XDEFINE')
@xdefine_var = "" if @xdefine_var.nil?
@custom_var = ScriptUtility.acquire_variable(path, 'CUSTOM')
@custom_var = "" if @custom_var.nil?
@archive = ScriptUtility.acquire_variable(path, 'ARCHIVE')
#Add the VSI.nul object to the CUSTOM variable if on TESTER_BASE has been determined.
tester_base = ScriptUtility.acquire_variable(path, 'TESTER_BASE')
if @archive == nil
#Deal with the QA Items
RageGen2010ProjectLoader.log.info("Deal with the QA Items ? What? speak English!!!!")
process_qa_items(path)
end
#Acquire a list of all the pertinent environment variables here.
@xproj_var = ScriptUtility.acquire_variable(path, 'XPROJ')
@xproj_var = "" if @xproj_var.nil?
@xinclude_var = ScriptUtility.acquire_variable(path, 'XINCLUDE')
@xinclude_var = "" if @xinclude_var.nil?
@temp_additional_includes = []
@temp_additional_includes = @xproj_var.split(" ")
@temp_additional_includes.concat(@xinclude_var.split(" "))
@force_include = ScriptUtility.acquire_variable(path, 'FORCE_INCLUDE')
@force_include = "" if @force_include.nil?
@xbox_title_id = ScriptUtility.acquire_variable(path, 'XBOX_TITLE_ID')
@xbox_spa_path = ScriptUtility.acquire_variable(path, 'XBOX_SPA_PATH')
@warning_level = ScriptUtility.acquire_variable(path, 'WARNINGS')
@parser_files = ScriptUtility.acquire_variable(path, 'PARSE')
@output_name_pattern_var = ScriptUtility.acquire_variable(path, 'OUTPUT_NAME_PATTERN')
@additional_includes = []
@temp_additional_includes.each do |include|
include = ScriptUtility.find_include_definition( include )
found_duplicate = false
@additional_includes.each do |added_include|
if include.eql?(added_include) == true
found_duplicate = true
break
end
end
if found_duplicate == false
@additional_includes.insert(@additional_includes.size, include)
end
end
end
# supports import method
def determine_tester_templates()
ENV["TESTERS"] = @testers
@tester_array = @testers.split(" ")
@process_array = @tester_array
@process_array << @archive if @archive != nil
end
# supports import method
def import_template_vcprojs( path, output_format, options )
projects = []
@process_array.each do |process_project|
process_project += VSProjShared.get_project_suffix_2010(output_format)
vcproj = OS::Path::combine(@working_directory, process_project)
RageGen2010ProjectLoader.log.info("Importing vcproj #{vcproj} path #{path} output_format #{output_format}")
result, project = import_project(path, vcproj, output_format, options)
projects << project if result == true
RageGen2010ProjectLoader.log.info("Importing FAILED!!!!!!!!!!!!!!!!!!!") unless result == true
end
projects
end
#==================================================================
# DW - this is the meat, reads makefile & template .vcproj together
def import( path, output_format, options )
@working_directory = File.dirname(path)
# 1. read makefile varibles.
read_makefile(path)
# 2. work out the lst of templates to use
determine_tester_templates()
# 3. import the vcproj projects
projects = import_template_vcprojs( path, output_format, options )
projects
end
# support method for import_project
def get_selected_template(path, output_name, options)
selected_template = nil
if options[:template].nil? == false and File.exist?(options[:template]) == true
projbuild_root = Globals::instance().toolsconfig + "/projbuild"
selected_template = OS::Path::combine(projbuild_root, selected_template)
else
selected_template = ScriptUtility.determine_project_template(path, output_name)
end
end
# get the template filename, return nil if it doesn't exist
def get_template_filename( selected_template, output_format )
RageGen2010ProjectLoader.log.info("get_template_filename output_format #{output_format}")
if File.exists?(selected_template) == false
template_filename = selected_template + VSProjShared.get_project_suffix_2010(output_format)
RageGen2010ProjectLoader.log.info("template_filename is #{template_filename}")
if template_filename.nil?
RageGen2010ProjectLoader.log.info("templeate filename is nil")
RageGen2010ProjectLoader.log.error("Unable to properly acquire a template file!")
return nil
elsif File.exists?(template_filename) == false
RageGen2010ProjectLoader.log.info("templeate filename exists #{template_filename}")
print "Unable to find template file: #{template_filename}.\n"
RageGen2010ProjectLoader.log.error("Unable to find template file #{template_filename}!")
return nil
end
end
template_filename
end
def get_makefile_expanded_files(path)
expanded_files = [] # A list of all files with their extensions to add to the project
combined_files_value = ScriptUtility.acquire_variable( path, "FILES" )
if combined_files_value != nil
value_files = combined_files_value.split(" ")
value_files.each do |value_file|
filename = OS::Path::combine(@working_directory, value_file)
filename = File.expand_path(filename)
find_files(filename, ".h", expanded_files)
find_files(filename, ".c", expanded_files)
find_files(filename, ".cpp", expanded_files)
if File.exist?(filename)
expanded_files << value_file
end
end
end
#Find a list of all header files included in this combined file.
combined_files_value = ScriptUtility.acquire_variable( path, "HEADONLY" )
if combined_files_value != nil
RageGen2010ProjectLoader.log.info("acquired combined_files_value1")
header_files = combined_files_value.split(" ")
header_files.each do |header_file|
header_file = header_file + ".h"
expanded_files << header_file
end
end
combined_files_value = ScriptUtility.acquire_variable( path, "CCODEONLY" )
if combined_files_value != nil
c_files = combined_files_value.split(" ")
c_files.each do |c_file|
c_file = c_file + ".c"
expanded_files << c_file
end
end
combined_files_value = ScriptUtility.acquire_variable( path, "CODEONLY" )
if combined_files_value != nil
cpp_files = combined_files_value.split(" ")
cpp_files.each do |cpp_file|
#Ensure we're testing for existence from the correct root.
full_path_file = OS::Path::combine(output_path, cpp_file)
full_path_file = File.expand_path(full_path_file)
if File.exist?(full_path_file + ".cpp")
expanded_files << cpp_file + ".cpp"
elsif File.exist?(full_path_file + ".c")
expanded_files << cpp_file + ".c"
else File.exist?(full_path_file)
expanded_files << cpp_file
end
end
end
#Any additional custom files.
combined_files_value = @custom_var
if combined_files_value != nil
expanded_files += combined_files_value.split(" ")
end
#Additional Resource objects.
combined_files_value = ScriptUtility.acquire_variable( path, "RESOURCES" )
if combined_files_value != nil
expanded_files += combined_files_value.split(" ")
end
expanded_files
end
# get embedded shaders and append to the expanded files
def get_embedded_shaders_and_expanded_files(path,expanded_files)
#Additional Embedded Shaders.
embedded_shaders = nil
combined_files_value = ScriptUtility.acquire_variable( path, "EMBEDDEDSHADERS" )
if combined_files_value != nil
embedded_shaders = combined_files_value.split(" ")
expanded_files += embedded_shaders
end
embedded_shaders
end
def create_guid(output_name)
guid_filename = OS::Path::combine(@working_directory, output_name) + ".guid"
guid = VSProjShared.create_guid(guid_filename, @p4)
end
def get_guid_and_project_name_and_files( project_definition_file_name, path )
#Assume this is a project definition file.
files = File.readlines(project_definition_file_name)
project_name = files.delete_at(0).strip
guid = files.delete_at(0).strip
files.collect { |x|
x.strip!
}
guid_filename = OS::Path.remove_extension(path) + ".guid"
if File.exists?(guid_filename) then
guid = File.readlines(guid_filename)[0].upcase
RageGen2010ProjectLoader.log.info("guid filename #{guid_filename}, guid changed to: #{guid}")
else
RageGen2010ProjectLoader.log.info("guid filename #{guid_filename}, doesnt exist")
end
return guid, project_name, files
end
CONDITION = "'$(Configuration)|$(Platform)'"
def get_output_directory(doc, full_config)
node = doc.find("//Project/PropertyGroup/OutDir[@Condition=\"#{CONDITION}=='#{full_config}'\"]")
return node.to_a[0].content.gsub("\\","") if (node and node.to_a and node.to_a[0] and node.to_a[0].content)
return nil
end
def get_item_definition_group(doc, full_config)
node = doc.find("//Project/ItemDefinitionGroup[@Condition=\"#{CONDITION}=='#{full_config}'\"]")
node
end
def get_embedded_lib_var(path, platform)
@embedded_lib_var = nil
case platform
when :xbox360:
@embedded_lib_var_name = 'EMBEDDEDLIB_XENON'
when :ps3:
@embedded_lib_var_name = 'EMBEDDEDLIB_PSN'
when :win32
@embedded_lib_var_name = 'EMBEDDEDLIB_WIN32'
when :win64
@embedded_lib_var_name = 'EMBEDDEDLIB_WIN64'
end
@embedded_lib_var = ScriptUtility.acquire_variable(path, @embedded_lib_var_name) if @embedded_lib_var_name.nil?
@embedded_lib_var = "" if @embedded_lib_var.nil?
end
def get_ouput_pattern_variables(platform, platform_config)
output_pattern, output_pattern_pdb = nil, nil
if @output_name_pattern_var != nil
output_pattern_noext = @output_name_pattern_var
output_pattern_noext = output_pattern_noext.gsub(/PLATFORM_CONFIG/,platform_config) if platform_config != nil
output_pattern = ""
output_pattern_pdb = ""
case platform
when :xbox360:
output_pattern = output_pattern_noext.gsub(/EXT/,"xex")
when :ps3:
output_pattern = output_pattern_noext.gsub(/EXT/,"self")
when :psp2:
output_pattern = output_pattern_noext.gsub(/EXT/,"self")
else
output_pattern = output_pattern_noext.gsub(/EXT/,"exe")
end
output_pattern_pdb = output_pattern_noext.gsub(/EXT/,"pdb")
end
return output_pattern, output_pattern_pdb
end
def patch_additional_include_directories(node)
if @xproj_var != nil
setting = node.find_first("AdditionalIncludeDirectories")
if setting
setting.content += ";" + @additional_includes.join(";")
RageGen2010ProjectLoader.log.info("AdditionalIncludeDirectories => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (AdditionalIncludeDirectories) was not found")
end
else
RageGen2010ProjectLoader.log.info("Ignoring AdditionalIncludeDirectories - is this ok?")
end
end
def patch_force_include_files(node)
if @force_include != nil
setting = node.find_first("ForcedIncludeFiles")
if setting
setting.content = setting.content.gsub("FORCE_INCLUDE",@force_include)
RageGen2010ProjectLoader.log.info("ForcedIncludeFiles (#{@force_include}) => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting was not found")
end
else
RageGen2010ProjectLoader.log.info("Ignoring ForcedIncludeFiles - is this ok?")
end
end
def patch_preprocessor_definitions(node)
if @xdefine_var != nil
setting = node.find_first("PreprocessorDefinitions")
if setting
setting.content = setting.content.gsub!("XDEFINE",@xdefine_var)
RageGen2010ProjectLoader.log.info("PreprocessorDefinitions => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (PreprocessorDefinitions) was not found")
end
else
RageGen2010ProjectLoader.log.info("Ignoring PreprocessorDefinitions - is this ok?")
end
end
def patch_program_database_filename( node, output_name, output_pattern_pdb )
setting = node.find_first("ProgramDataBaseFileName")
if setting
if output_pattern_pdb.nil?
setting.content = setting.content.gsub!("OUTPUT_FILE_NAME", output_name)
setting.content = setting.content.gsub!(template_name, output_name)
else
setting.content = output_pattern_pdb
end
RageGen2010ProjectLoader.log.info("ProgramDataBaseFileName => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (ProgramDataBaseFileName) was not found")
end
end
def patch_warning_level( node )
if @warning_level != nil
setting = node.find_first("WarningLevel")
if setting
setting.content = @warning_level
RageGen2010ProjectLoader.log.info("WarningLevel => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (WarningLevel) was not found")
end
else
RageGen2010ProjectLoader.log.info("Ignoring warning level - is this ok?")
end
end
def patch_output_file( node, output_name, output_pattern )
setting = node.find_first("OutputFile")
if (setting)
if output_pattern.nil?
setting.content = setting.content.gsub("OUTPUT_FILE_NAME", output_name)
setting.content = setting.content.gsub(template_name, output_name)
else
setting.content = output_pattern
end
RageGen2010ProjectLoader.log.info("OutputFile => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (OutputFile) was not found")
end
end
def patch_additional_dependencies( node )
if @embedded_lib_var != nil
setting = node.find_first("AdditionalDependencies")
setting.content = setting.content.gsub(@embedded_lib_var_name, @embedded_lib_var.split(" ").join(";"))
RageGen2010ProjectLoader.log.info("AdditionalDependencies => #{setting.content}")
else
RageGen2010ProjectLoader.log.info("Ignoring AdditionalDependencies - is this ok?")
end
end
def patch_deployment_files(node)
setting = node.find_first("DeploymentFiles")
if setting
replaceval = ENV['XBOX_DEPLOYMENT_FILES']
replaceval = "" if replaceval == nil
setting.content = setting.content.gsub("XBOX_DEPLOYMENT_FILES",replaceval)
RageGen2010ProjectLoader.log.info("DeploymentFiles => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (DeploymentFiles) was not found")
end
end
def patch_imagexex_output_filename( node, output_name, output_pattern )
# DW - Hrm - its not clear what needs done here
# if output_pattern.nil?
# setting = node.find_first("OutputFileName")
# if setting
# setting.content = setting.content.gsub("OUTPUT_FILE_NAME", output_name)
# RageGen2010ProjectLoader.log.info("OutputFileName => #{setting.content}")
# else
# RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (OutputFileName) was not found")
# end
# else
# node.attributes["OutputFileName"] = output_pattern
# end
end
def patch_imagexex_additional_sections(node)
setting = node.find_first("AdditionalSections")
if ( setting and @xbox_title_id != nil and @xbox_spa_path != nil )
setting.content = setting.content.gsub("XboxSpaLinkOpt","#{@xbox_title_id}=#{@xbox_spa_path}")
RageGen2010ProjectLoader.log.info("AdditionalSections => #{setting.content}")
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (AdditionalSections) was not found")
end
end
def patch_imagexex_title_id(node)
setting = node.find_first("TitleID")
if setting and @xbox_title_id != nil
#Backwards Compatibility - if the title id does not have 0x prefix in front of it.
if @xbox_title_id.index("0x") != 0
setting.content = setting.content.gsub("XboxTitleId", "0x" + @xbox_title_id)
else
setting.content = setting.content.gsub("XboxTitleId", @xbox_title_id)
end
RageGen2010ProjectLoader.log.info("XboxTitleId => #{setting.content}")
else
RageGen2010ProjectLoader.log.info("Ignoring TitleID - is this ok?")
end
end
def patch_imagexex_project_defaults(node)
setting = node.find_first("ProjectDefaults")
if (setting)
setting.content = setting.content.gsub("XboxImageXexConfig","")
RageGen2010ProjectLoader.log.info("ProjectDefaults => #{setting.content}")
end
end
def patch_prebuild_event(node)
if @parser_files != nil
#Add pre-build event attributes
setting = node.find_first("CommandLine")
if (setting)
setting.content = setting.content + "\n" + '$(RS_TOOLSROOT)\\bin\\coding\\python\\parCodeGen.exe ' + @parser_files
RageGen2010ProjectLoader.log.info("CommandLine => #{setting.content}")
setting = node.find_first("Description")
setting.content = "Executing pre-build steps and generating parser code..."
else
RageGen2010ProjectLoader.log.error("ERROR ERROR ERROR! - a setting (CommandLine) was not found")
end
else
RageGen2010ProjectLoader.log.info("Ignoring parser_files prebuild event - is this ok?")
end
end
def set_name(doc, project_name)
doc.root.attributes["Name"] = project_name
find_node = doc.find_first("//Project[@Name]")
RageGen2010ProjectLoader.log.error("Error didn't write the name") if find_node.nil?
end
def set_guid(doc, guid)
doc.root.attributes["ProjectGUID"] = "{#{guid}}"
find_node = doc.find_first("//Project[@ProjectGUID]")
RageGen2010ProjectLoader.log.error("Error didn't write the ProjectGUID") if find_node.nil?
end
def add_files_to_compile( doc, output_path, files )
file_node = doc.find_first("//Project")
RageGen2010ProjectLoader.log.error("Can't find project root node") unless file_node
files.each do |filename|
out_path = OS::Path.combine(output_path,filename)
out_path = File.expand_path(out_path)
out_path = OS::Path.make_relative(out_path,output_path)
out_path = OS::Path.dos_format(out_path)
item_group = XML::Node.new("ItemGroup")
new_node = XML::Node.new("ClCompile")
new_node["Include"] = out_path
item_group << new_node
RageGen2010ProjectLoader.log.info("Adding file #{out_path}")
do_some_embedded_shader_stuff_I_cant_yet_understand()
file_node << item_group
end
end
# DW - After modularising this I've discovered what this really does is it 'patches' the vcxproj in it's xml doc and adds files to the project.
def parse_template_append_details_and_save( doc, project_name, guid, embedded_shaders, expanded_files, selected_template, temporary_filename, path, output_name, files, output_path )
set_name(doc, project_name)
set_guid(doc, guid)
RageGen2010ProjectLoader.log.info("parse_template_append_details_and_save")
doc.find("/Project/ItemGroup/ProjectConfiguration").each do |config_node|
# 1. Get the full config
full_config = config_node.attributes["Include"]
RageGen2010ProjectLoader.log.info("Processing configuration #{full_config}")
# 2. Get the platform and config
platform,config = VSProjShared.parse_config_name(full_config)
platform_config = get_output_directory( doc, full_config )
next if platform_config.nil?
RageGen2010ProjectLoader.log.info("platform #{platform} config #{config} platform_config #{platform_config}")
# 3. Get embedded lib
get_embedded_lib_var(path, platform)
# 4. Get output pattern
output_pattern, output_pattern_pdb = get_ouput_pattern_variables(platform, platform_config)
RageGen2010ProjectLoader.log.info("output_pattern #{output_pattern} output_pattern_pdb #{output_pattern_pdb}")
# 5. Get item definition group - the settings for this full_config
nodes = get_item_definition_group(doc, full_config)
RageGen2010ProjectLoader.log.error("Cant find the node for #{full_config}" ) if nodes.nil?
RageGen2010ProjectLoader.log.info("#{nodes.length} #{nodes.class} configuration nodes to process")
nodes.each do |section|
section.each do |node|
RageGen2010ProjectLoader.log.info("Item definition group node found #{node.name}" )
case node.name
when "PreBuildEvent":
RageGen2010ProjectLoader.log.info("*****patch_prebuild_event*****")
patch_prebuild_event(node)
when "ClCompile": # VS2010
patch_additional_include_directories(node)
patch_force_include_files(node)
patch_preprocessor_definitions(node)
patch_program_database_filename(node, output_name,output_pattern_pdb)
patch_warning_level(node)
when "Link": # VS2010
patch_output_file(node,output_name,output_pattern)
patch_additional_dependencies(node)
when "ImageXex":
patch_imagexex_output_filename(node,output_name,output_pattern)
patch_imagexex_additional_sections(node)
patch_imagexex_title_id(node)
patch_imagexex_project_defaults(node)
when "Deploy":
patch_deployment_files(node)
when "text", "PostBuildEvent":
# deliberately ignored
else
RageGen2010ProjectLoader.log.error("Node #{node.name} was not processed. #{node}")
end
end
end
end
# Finally we add the files this project needs to buid
add_files_to_compile( doc, output_path, files )
RageGen2010ProjectLoader.log.info("Saving temporary file to #{temporary_filename}.")
doc.save(temporary_filename)
end
# DW : this is commented out until it can be understood.
def do_some_embedded_shader_stuff_I_cant_yet_understand()
=begin
#Add any custom file configurations for this file.
if embedded_shaders != nil
base_filename = File.basename(out_path)
embedded_shaders.each do |embedded_shader|
if base_filename.eql?(embedded_shader) == true
embedded_shader = OS::Path::combine(@working_directory, embedded_shader)
#For every configuration add a new FileConfiguration
doc.find("/VisualStudioProject/Configurations/Configuration").each do |config_node|
config_name = config_node.attributes["Name"]
platform,target = VSProjShared.parse_config_name(config_name)
custom_step = Info::FxCustomBuild.new(embedded_shader, out_path, platform)
custom_step_node = custom_step.create_node()
file_configuration_node = XML::Node.new("FileConfiguration")
file_configuration_node["Name"] = config_name
file_configuration_node << custom_step_node
new_node << file_configuration_node
end
end
end
else
#For all non-standard files, look for a custom object in the projbuild root to use as a template.
extension = File.extname(filename)
extension = extension[1...extension.size]
if extension.eql?("cpp") == false and extension.eql?("c") == false and extension.eql?("h") == false and extension.eql?("nul") == false
custom_root = ScriptUtility.get_custom_root()
custom_path = OS::Path::combine(custom_root, "#{extension}.custom")
full_path = OS::Path::combine(@working_directory, filename)
if File.exist?(custom_path) == true
#For every configuration add a new FileConfiguration
doc.find("/VisualStudioProject/Configurations/Configuration").each do |config_node|
config_name = config_node.attributes["Name"]
file_configuration = CustomBuildStep::get_file_configuration(custom_path, full_path, config_name)
next if file_configuration.nil?
file_configuration_node = XML::Node.new("FileConfiguration")
tool_node = XML::Node.new(file_configuration)
file_configuration_node["Name"] = config_name
file_configuration_node << tool_node
new_node << file_configuration_node
end
end
end
end
=end
end
# import a vcproj
def import_project(path, output, output_format, options)
return false if File.exists?(path) == false
RageGen2010ProjectLoader.log.info("Importing #{path}")
# 0. extract sundry info from params
version_suffix = VSProjShared.get_project_suffix_2010(output_format)
output_name = File.basename(output, version_suffix) #Remove the version suffix.
output_path = OS::Path.get_directory(output)
# 1. Get the selected template
selected_template = get_selected_template(path, output_name, options)
return true if selected_template.nil? #Defer this to possibly another generator. This is not an error.
RageGen2010ProjectLoader.log.info("Trying to import #{path} with ragegen project loader. the selected_template is #{selected_template}")
# 2. Get the template filename
template_filename = get_template_filename( selected_template, output_format )
return false if template_filename.nil?
@template_name = File.basename(selected_template)
# 3. Get files in the makefile
expanded_files = get_makefile_expanded_files(path)
# 4. Get embedded shaders
embedded_shaders = get_embedded_shaders_and_expanded_files(path,expanded_files)
RageGen2010ProjectLoader.log.info("Checking template: #{template_filename}.")
# 5. Load the xml file that is the template vcproj file
parser = XML::Parser.file(template_filename)
doc = parser.parse
# 6. Check the version
#Dw - todo support VS2010 properly ... /Project/PropertyGroup/_ProjectFileVersion>10.0.30319.1
#correct_version = VSProjShared.get_version(output_format)
#if doc.root.attributes["Version"] != correct_version then
# RageGen2010ProjectLoader.log.error("Template is not the correct Visual Studio version: #{doc.root.attributes['Version']} not #{correct_version}.")
# return false
#end
# 7. Get guid
guid = create_guid(output_name)
project_definition_file_name = create_project_definition_file(@working_directory, output_name, guid, expanded_files)
return false if File.exists?(project_definition_file_name) == false
RageGen2010ProjectLoader.log.info("Project definition file at: #{project_definition_file_name} exists - it was created - for what reason I don;t know")
guid, project_name,files = get_guid_and_project_name_and_files( project_definition_file_name, path )
File.delete(project_definition_file_name)
# 8. The template is parsed for specific settings then as these settings are read we consider the state of the ragegen2010 calss and write back into the xml doc
# eventually it is saved and then is reloaded so that it can be loaded as an internal representation of the project. A bit too elaborate for my liking but anyway...
temporary_filename = OS::Path.combine(Globals::instance().toolstemp,"temp.vcxproj")
RageGen2010ProjectLoader.log.info("Filling temporary vcproj #{temporary_filename}.")
parse_template_append_details_and_save( doc, project_name, guid, embedded_shaders, expanded_files, selected_template, temporary_filename, path, output_name, files, output_path )
# 9. Load / import the temp vcproj - and we now have an internal representation of the rage gen 2010 format.
RageGen2010ProjectLoader.log.info("Passing #{temporary_filename} to Visual Studio loader.")
if output_format == :vs2005
result, curr_project = VS2005VSProjLoader.new().import(temporary_filename, output_path)
elsif output_format == :vs2008
result, curr_project = VS2008VSProjLoader.new().import(temporary_filename, output_path)
elsif output_format == :vs2010
result, curr_project = VS2010VSProjLoader.new().import(temporary_filename, output_path)
end
# this is a hack to deal with linker librarys in VS2010.
=begin
RageGen2010ProjectLoader.log.info("DW attempting to add to the doc the library dependencies")
testers_var = ScriptUtility.acquire_variable(path, 'TESTERS')
testers_var = "" if testers_var.nil?
RageGen2010SolutionLoader.log.info("DW attempting to add to the doc the library dependencies testers_var #{testers_var}")
archive = ScriptUtility.acquire_variable(path, 'ARCHIVE')
testers_var += " " + archive if archive.nil? == false
@tester_array = testers_var.split(" ")
@working_directory = File.dirname(path)
build_data = ProjBuildData::instance()
build_data.reset
success = true
projects = Array.new()
@tester_array.each do |tester|
RageGen2010SolutionLoader.log.info("DW attempting to add to the doc the library dependencies : running tester #{tester}")
basename = OS::Path.get_basename(tester)
libs = ScriptUtility.acquire_expanded_libs(path, basename)
RageGen2010SolutionLoader.log.info("libs #{libs.length} #{libs}")
Dir.chdir(OS::Path.get_directory(path)) {
if libs != nil
libs.each { |lib|
lib_name = OS::Path.get_basename(lib)
lib = OS::Path.normalise(lib)
guid = nil
guid_filename = nil
lib = OS::Path.remove_extension(lib)
lib = File.expand_path(lib)
guid_filename = "#{lib}.guid"
guid_filename = OS::Path::make_relative( guid_filename, @working_directory )
guid = VSProjShared.create_guid(guid_filename, @p4)
if guid == nil
RageGen2010SolutionLoader.log.debug("Unable to acquire guid #{guid_filename}!")
print "Unable to acquire guid #{guid_filename}!\n"
return
end
guid = guid.strip.upcase
child_project = Info::Project.new(lib_name)
child_project.guid = guid
child_project.path = OS::Path.get_directory(guid_filename)
search_guid = child_project.guid[1..-2]
ignore_guids = ENV['IGNORE_GUIDS']
ignore_guids = ScriptUtility.acquire_variable(path, 'IGNORE_GUIDS') if ignore_guids == nil
#Assume that the startup project is dependent on all child projects.
if ignore_guids == nil or ignore_guids.index(search_guid) == nil then
curr_project.dep_guids << child_project.guid
end
RageGen2010SolutionLoader.log.info("#Adding dependent project #{child_project.guid} #{child_project}")
build_data.dependent_projects[child_project.guid] = child_project
RageGen2010SolutionLoader.log.info("curr_project.config.xml_data #{curr_project.config.xml_data}")
project_refs_node = XML::Node.new("ProjectReferences")
project_ref_node = XML::Node.new("ProjectReference")
project_node = XML::Node.new("Project")
project_node.content = "#{child_project.guid}"
project_ref_node["Include"] = "#{child_project.path}/#{lib_name}_2010.vcxproj"
project_ref_node << project_node
project_refs_node << project_ref_node
curr_project.config.xml_data << project_refs_node
RageGen2010SolutionLoader.log.info("curr_project.config.xml_data #{curr_project.config.xml_data}")
#curr_project.config.xml_data.find("ProjectReferences/ProjectReference")
}
end
}
end
=end
return result, curr_project
end
end
class RageGen2010Generator
@@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 export( path, project, options = nil )
true
end
def import( path, options = nil )
return false if options == nil
case options[:type]
when :solution:
loader = RageGen2010SolutionLoader.new()
return loader.import(path, options[:out_format], options)
when :project:
RageGen2010ProjectLoader.log.info("importing a ragegen project")
loader = RageGen2010ProjectLoader.new()
return loader.import(path, options[:out_format], options)
end
false
end
end
end #module ProjBuild
end #module Pipeline