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