1128 lines
33 KiB
Ruby
Executable File
1128 lines
33 KiB
Ruby
Executable File
require 'xml'
|
|
require 'active_support/ordered_hash'
|
|
require 'pipeline/coding/projbuild/project'
|
|
require 'pipeline/coding/xml2vsxml'
|
|
require "pipeline/coding/projbuild/generators/vs2005"
|
|
require "pipeline/coding/projbuild/generators/internal"
|
|
require 'pipeline/config/projects'
|
|
require 'pipeline/os/path'
|
|
|
|
module Pipeline
|
|
|
|
module ProjBuild
|
|
|
|
class LineReader
|
|
|
|
attr_accessor :unity_build_filenames # if true filenames that are created have "_unity" in them.
|
|
|
|
attr_reader :i, :lines ,:path, :filename, :filepath
|
|
attr_writer :path, :filename, :filepath
|
|
|
|
def initialize( filename )
|
|
|
|
@filename = filename
|
|
@filepath = ""
|
|
@path = OS::Path.get_directory(filename)
|
|
@lines = File.readlines(filename)
|
|
@i = 0
|
|
end
|
|
|
|
def lines_left?()
|
|
|
|
(@i < @lines.size)
|
|
end
|
|
|
|
def current_line()
|
|
|
|
lines[@i]
|
|
end
|
|
|
|
def increment_line()
|
|
|
|
@i = @i + 1
|
|
end
|
|
|
|
def read_into_section()
|
|
|
|
while current_line != nil and current_line.index("{") == nil
|
|
|
|
self.increment_line
|
|
end
|
|
|
|
self.increment_line
|
|
end
|
|
end
|
|
|
|
class RageProjBuilderLoader < VSProjShared
|
|
|
|
@@log = nil
|
|
|
|
attr_reader :curr_project, :pre_build_steps
|
|
|
|
def RageProjBuilderLoader.log
|
|
|
|
@@log = Log.new( 'rageprojbuilderloader' ) if @@log == nil
|
|
@@log
|
|
end
|
|
|
|
def initialize(vs2010 = false)
|
|
|
|
@vs2010 = vs2010
|
|
|
|
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()
|
|
|
|
@output_file = nil
|
|
end
|
|
|
|
def output_file
|
|
return @output_file
|
|
end
|
|
|
|
def import( path, options )
|
|
|
|
return false if File.exists?(path) == false
|
|
return false if OS::Path.get_extension(path) != "txt"
|
|
|
|
RageProjBuilderLoader.log.debug("trying to import #{path} with rage projbuilder loader")
|
|
|
|
@curr_project = Info::Project.new(nil)
|
|
|
|
#Gives us default configuration...
|
|
#RageProjBuilderLoader.log.info("RageProjBuilderLoader.import acquire_configuration_template #{path}")
|
|
configuration_template = acquire_configuration_template(LineReader.new(path))
|
|
#RageProjBuilderLoader.log.info("RageProjBuilderLoader.import acquire_configuration_template is #{configuration_template}")
|
|
parser = XML::Parser.file(configuration_template)
|
|
doc = parser.parse
|
|
#RageProjBuilderLoader.log.info("RageProjBuilderLoader.import import_configurable")
|
|
ProjBuildImporter.new().import_configurable(@curr_project,doc.root)
|
|
|
|
@curr_project.path = OS::Path.normalise(OS::Path.get_directory(path))
|
|
@unity_enabled = options[:unity_build_enabled]
|
|
# print "RageProjBuilder.import - Unity Build Enabled: #{@unity_enabled}\n"
|
|
|
|
@force_includes = Array.new()
|
|
@precompiled_header = nil
|
|
@pre_build_steps = Array.new()
|
|
@parser_output = nil
|
|
@defines = ActiveSupport::OrderedHash.new()
|
|
@project_references = Array.new()
|
|
@configuration_type = nil
|
|
@output_file_name = nil
|
|
@warning_level = nil
|
|
@warnings_as_errors = nil
|
|
@module_definition_file = nil
|
|
@xbox_title_id = nil
|
|
@xbox_spa_path = nil
|
|
|
|
preparse(@curr_project,LineReader.new(path),true)
|
|
|
|
defines_node = XML::Node.new("defines")
|
|
|
|
@defines.keys.each { |define|
|
|
|
|
define_node = XML::Node.new("define")
|
|
define_node["value"] = define
|
|
|
|
defines_node << define_node
|
|
}
|
|
|
|
@curr_project.config.root_node() << defines_node
|
|
|
|
#RageProjBuilderLoader.log.info("Add all project references to the project. Only a Visual Studio 2010-supported (or C#) option")
|
|
project_refs_node = XML::Node.new("ProjectReferences")
|
|
@project_references.each { |project_reference|
|
|
#RageProjBuilderLoader.log.info("project_reference #{project_reference}")
|
|
project_reference_node = XML::Node.new("ProjectReference")
|
|
project_reference_node["path"] = project_reference
|
|
project_refs_node << project_reference_node
|
|
}
|
|
|
|
@curr_project.config.root_node() << project_refs_node
|
|
|
|
#Validate that every file here exists. If not, then mark a warning -- this is not an error.
|
|
if @curr_project.files != nil
|
|
|
|
@working_directory = File.dirname(path)
|
|
@curr_project.files.size.times do |index|
|
|
|
|
file = @curr_project.files[index]
|
|
full_path = OS::Path::combine(@working_directory, file.path)
|
|
|
|
if File.exist?(full_path) == false
|
|
|
|
warning_message = "Project was unable to find #{full_path}!"# Omitting from the project."
|
|
RageProjBuilderLoader.log.error(warning_message)
|
|
print warning_message + "\n"
|
|
|
|
#@curr_project.files[index] = nil
|
|
end
|
|
end
|
|
|
|
#Remove all 'nil' entries from the array.
|
|
@curr_project.files.compact!
|
|
end
|
|
|
|
@curr_project.config.root_node()["type"] = @configuration_type if @configuration_type != nil
|
|
@curr_project.config.root_node()["type"] = "library" if @configuration_type.nil?
|
|
|
|
@curr_project.config.root_node()["output_file_name"] = @output_file_name if @output_file_name != nil
|
|
@curr_project.config.root_node()["warning_level"] = @warning_level if @warning_level != nil
|
|
@curr_project.config.root_node()["warnings_as_errors"] = @warnings_as_errors if @warnings_as_errors != nil
|
|
@curr_project.config.root_node()["module_definition_file"] = @module_definition_file if @module_definition_file != nil
|
|
@curr_project.config.root_node()["xbox_title_id"] = @xbox_title_id if @xbox_title_id != nil
|
|
@curr_project.config.root_node()["xbox_spa_path"] = @xbox_spa_path if @xbox_spa_path != nil
|
|
|
|
#fixup...
|
|
|
|
if @pre_build_steps.size > 0 then
|
|
|
|
@curr_project.config.root_node() << Info::PreBuild.new(@pre_build_steps).create_node()
|
|
end
|
|
|
|
if @force_includes.size > 0 then
|
|
|
|
@curr_project.config.root_node() << Info::ForceIncludes.new(@force_includes).create_node()
|
|
end
|
|
|
|
if @precompiled_header != nil then
|
|
|
|
@curr_project.platforms.each { |platform_sym,platform|
|
|
|
|
next if platform_sym == :win32 or platform_sym == :win64
|
|
|
|
platform.config.root_node["precompiled_header"] = @precompiled_header
|
|
platform.config.root_node["precompiled_header_source"] = OS::Path.remove_extension(@precompiled_header) + ".cpp"
|
|
}
|
|
end
|
|
|
|
if @curr_project.name.nil?
|
|
@output_file = nil
|
|
RageProjBuilderLoader.log.error("Project name has not been specified. Use the \"Project\" keyword in #{path}. Project will not be generated!")
|
|
return true; #Do not attempt to generate a project without a name; this is not an exporting error as another higher-level project may be using it.
|
|
end
|
|
|
|
if @curr_project.files.nil? or ( @curr_project.files.size == 0 and @curr_project.filters.size == 0 )
|
|
@output_file = nil
|
|
RageProjBuilderLoader.log.error("Project has no files or directories. Project file will not generated!")
|
|
return true #There are no files in the root directory, but may be files within separte filters/directories.
|
|
end
|
|
|
|
guid_filename = OS::Path::combine(File.dirname(path), @curr_project.name) + ".guid"
|
|
|
|
#When importing a project internally, the normal system will create GUID file. Instead of
|
|
#throwing around these unused guid files everywhere, track if it should be deleted after created.
|
|
#If the GUID doesn't exist, then delete the newly generated one. Otherwise, don't do anything in
|
|
#the case this is used to generate its own project.
|
|
delete_guid_file = false
|
|
if options != nil and options[:deleteguidfile] != nil and options[:deleteguidfile] == true then
|
|
if File.exists?(guid_filename) == false
|
|
delete_guid_file = true
|
|
end
|
|
end
|
|
|
|
guid = VSProjShared.create_guid(guid_filename, nil)
|
|
|
|
if delete_guid_file == true then
|
|
File.delete(guid_filename)
|
|
end
|
|
|
|
@curr_project.guid = guid
|
|
ProjBuildData::instance().projects[guid] = @curr_project
|
|
|
|
projects = Array.new()
|
|
projects << @curr_project
|
|
|
|
return true, projects
|
|
end
|
|
|
|
protected
|
|
|
|
def add_custom_build( file_info, path )
|
|
|
|
RageProjBuilderLoader.log.debug("adding custom data for #{path}")
|
|
# RageProjBuilderLoader.log.error("Unity Enabled: #{@unity_enabled}\n")
|
|
|
|
xml_node = nil
|
|
|
|
case OS::Path.get_extension(path)
|
|
|
|
when "job":
|
|
|
|
if not @unity_enabled then
|
|
custom_build = Info::JobCustomBuild.new(path, file_info)
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[:ps3].config.root_node() << xml_node if xml_node != nil
|
|
end
|
|
when "frag":
|
|
|
|
if not @unity_enabled then
|
|
custom_build = Info::FragCustomBuild.new(path)
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[:ps3].config.root_node() << xml_node if xml_node != nil
|
|
end
|
|
when "task":
|
|
|
|
if not @unity_enabled then
|
|
custom_build = Info::TaskCustomBuild.new(path)
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[:ps3].config.root_node() << xml_node if xml_node != nil
|
|
end
|
|
when "fx":
|
|
|
|
platformInfo = Info::PlatformInfo.instance()
|
|
|
|
platformInfo.platforms.keys.each { |platform_sym|
|
|
|
|
custom_build = Info::FxCustomBuild.new(path, file_info.path, platform_sym)
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[platform_sym].config.root_node() << xml_node if xml_node != nil
|
|
}
|
|
else
|
|
#RageProjBuilderLoader.log.error("unknown custom file type #{OS::Path.get_extension(path)}")
|
|
#print "Could not find custom build step for #{file_info.path}!\n"
|
|
end
|
|
end
|
|
|
|
def import_directories( line_reader, filter )
|
|
|
|
RageProjBuilderLoader.log.debug("import_directories #{line_reader.filename} #{line_reader.i}")
|
|
|
|
while line_reader.lines_left?
|
|
|
|
line = line_reader.current_line.strip
|
|
|
|
if line == "" or line == nil then
|
|
|
|
line_reader.increment_line
|
|
next
|
|
end
|
|
|
|
tokens = line.split(" ")
|
|
|
|
if tokens.last == "}" then
|
|
|
|
line_reader.increment_line
|
|
break
|
|
else
|
|
|
|
loadpath = File.expand_path(OS::Path.combine(line_reader.path,line,"makefile.txt"))
|
|
|
|
if File.exists?(loadpath) == false then
|
|
|
|
RageProjBuilderLoader.log.error("import_directories failed to read #{loadpath} from within #{line_reader.filename}")
|
|
else
|
|
|
|
#Directories are specified in path form, such as ..\..\atl.
|
|
#The name of the Filter in the solution will be the basename of this path -- not the full path (e.g. atl).
|
|
#
|
|
new_filter = Info::Filter.new( File.basename(line) )
|
|
RageProjBuilderLoader.log.debug("import_directories new import_files on #{loadpath}")
|
|
preparse(new_filter,LineReader.new(loadpath))
|
|
filter.filters << new_filter
|
|
|
|
# Hack for filters
|
|
if (line.include?('..\\..\\'))
|
|
filter.filters << Info::Filter.new("..//..//")
|
|
end
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
end
|
|
end
|
|
|
|
def do_parse( filter, line_reader )
|
|
|
|
line_reader.read_into_section
|
|
|
|
rel_path = OS::Path.make_relative(line_reader.path,@curr_project.path)
|
|
|
|
@last_parse_path = line_reader.path
|
|
dirName = OS::Path.dos_format(rel_path)
|
|
if dirName == "" then
|
|
dirName = "."
|
|
end
|
|
@pre_build_steps << "pushd #{dirName}"
|
|
parCodeGenCommand = "$(RS_TOOLSROOT)\\bin\\coding\\python\\parCodeGen.exe"
|
|
@pre_build_steps << parCodeGenCommand
|
|
|
|
if @parser_output == nil then
|
|
|
|
@parser_output = Info::Filter.new("[Parser Files]")
|
|
@parser_output.path = ""#line_reader.path
|
|
@curr_project.filters.insert(0,@parser_output)
|
|
end
|
|
|
|
import_files(:parse,filter,line_reader)
|
|
|
|
if @pre_build_steps[-1] == parCodeGenCommand then
|
|
# nothing changed (no args got appended to the command), so remove it
|
|
@pre_build_steps.pop()
|
|
end
|
|
|
|
@pre_build_steps << "popd"
|
|
end
|
|
|
|
#Takes a base filter and merges all of the imported_filter's data in.
|
|
def import_filters(root_path, relative_path, base_filter, imported_filters )
|
|
|
|
imported_filters.filters.each do |filter|
|
|
|
|
if filter.filters != nil
|
|
import_filters(root_path, relative_path, nil, filter)
|
|
end
|
|
|
|
filter.files.each do |file|
|
|
|
|
filename = OS::Path.combine(relative_path, file.path)
|
|
|
|
full_path = File.expand_path(OS::Path.combine(root_path,filename))
|
|
rel_path = OS::Path.make_relative(full_path,@curr_project.path)
|
|
file.path = rel_path
|
|
end
|
|
|
|
if base_filter != nil then
|
|
base_filter << filter
|
|
end
|
|
end
|
|
end
|
|
|
|
def import_files( file_type, filter, line_reader )
|
|
|
|
RageProjBuilderLoader.log.debug("import_files #{file_type.to_s} #{line_reader.filename} #{line_reader.i}")
|
|
|
|
while line_reader.lines_left?
|
|
|
|
RageProjBuilderLoader.log.debug("import_files line #{line_reader.filename} #{line_reader.i}")
|
|
|
|
line = line_reader.current_line.strip
|
|
|
|
if line == "" or line == nil or line.index("#") == 0 then
|
|
|
|
line_reader.increment_line
|
|
next
|
|
end
|
|
|
|
tokens = line.split(" ")
|
|
|
|
#The project definition format entirely relies on space-separated words.
|
|
#But in the case that we want to have spaces in names of files, directories or filters,
|
|
#we have to handle this case uniquely. Ugh. This parsing method entirely is due for revisiting.
|
|
quote_array = line.split("\"")
|
|
tokens[1] = quote_array[1] if quote_array.size > 1
|
|
|
|
foundNewSection = true
|
|
|
|
case tokens[0]
|
|
|
|
when "Files"
|
|
|
|
line_reader.read_into_section
|
|
store_path = line_reader.path
|
|
line_reader.path = OS::Path.combine(line_reader.path,line_reader.filepath)
|
|
import_files(:files,filter,line_reader)
|
|
line_reader.path = store_path
|
|
|
|
when "Include"
|
|
|
|
#Works initially like the "Directory" directive and creates a new filter
|
|
#to then import all data from the specified project definition file.
|
|
|
|
#First, acquire the project definition path.
|
|
makefile_path = tokens[1]
|
|
filter_name = OS::Path.get_directory(tokens[1])
|
|
if filter_name == tokens[1]
|
|
#Presume that a directory has been specified instead of a file.
|
|
#Assume that the file's name is makefile.txt
|
|
makefile_path = OS::Path.combine(makefile_path, "makefile.txt")
|
|
end
|
|
|
|
makefile_path = OS::Path.combine(line_reader.path, makefile_path)
|
|
makefile_path = File.expand_path(makefile_path)
|
|
if File.exists?(makefile_path) == false
|
|
|
|
RageProjBuilderLoader.log.error("Unable to find include project definition file #{makefile_path}!")
|
|
return
|
|
end
|
|
|
|
#Determine the name of the newly created filter to include these files under.
|
|
#If no filter is specified, then assume they will go to the root.
|
|
new_filter = nil
|
|
if filter_name.nil? == true or filter_name == ""
|
|
filter_name = ""
|
|
new_filter = filter.filters
|
|
else
|
|
new_filter = Info::Filter.new(filter_name)
|
|
end
|
|
|
|
newBuilder = RageProjBuilderLoader.new(@vs2010)
|
|
options = Hash.new()
|
|
options[:ignorevsi] = true
|
|
options[:deleteguidfile] = true #Do not let unnecesary GUID files linger.
|
|
options[:unity_build_enabled] = @unity_enabled
|
|
|
|
if newBuilder.import(makefile_path, options) == false then
|
|
RageProjBuilderLoader.log.error("Unable to parse included files #{makefile_path}!")
|
|
return
|
|
end
|
|
|
|
#Convert the newly imported project file to have the correct paths.
|
|
makefile_directory = OS::Path.get_directory(makefile_path)
|
|
root_relative_path = OS::Path.make_relative(makefile_directory, line_reader.path) #This is the relative path from the RootDirectory of the project.
|
|
|
|
newBuilder.curr_project.files.each do |file|
|
|
|
|
filename = OS::Path.combine(root_relative_path, file.path)
|
|
full_path = File.expand_path(OS::Path.combine(line_reader.path,filename))
|
|
rel_path = OS::Path.make_relative(full_path,@curr_project.path)
|
|
file.path = rel_path
|
|
new_filter.files << file
|
|
end
|
|
|
|
import_filters(line_reader.path, root_relative_path , new_filter.filters, newBuilder.curr_project)
|
|
|
|
relative_path = OS::Path.make_relative(makefile_directory, @curr_project.path)
|
|
@pre_build_steps << "pushd #{OS::Path.dos_format(relative_path)}"
|
|
@pre_build_steps = @pre_build_steps + newBuilder.pre_build_steps
|
|
@pre_build_steps << "popd"
|
|
|
|
filter.filters << new_filter
|
|
|
|
#No more processing is necessary.
|
|
line_reader.increment_line
|
|
next
|
|
|
|
when "Custom"
|
|
|
|
line_reader.read_into_section
|
|
import_files(:custom,filter,line_reader)
|
|
when "Embedded"
|
|
|
|
line_reader.read_into_section
|
|
import_files(:embedded,filter,line_reader)
|
|
when "Directory"
|
|
|
|
line_reader.read_into_section
|
|
|
|
new_filter = Info::Filter.new(tokens[1])
|
|
store_path = line_reader.path
|
|
line_reader.path = OS::Path.combine(line_reader.path,tokens[1])
|
|
import_files(file_type,new_filter,line_reader)
|
|
line_reader.path = store_path
|
|
filter.filters << new_filter
|
|
when "Folder"
|
|
|
|
#creates a filter without navigating down another folder in the file directory structure...
|
|
line_reader.read_into_section
|
|
new_filter = Info::Filter.new(tokens[1])
|
|
|
|
import_files(file_type,new_filter,line_reader)
|
|
filter.filters << new_filter
|
|
when "Parse"
|
|
|
|
do_parse(filter,line_reader)
|
|
|
|
else
|
|
|
|
foundNewSection = false
|
|
end
|
|
|
|
if foundNewSection == false then
|
|
|
|
if tokens.last == "}" then
|
|
|
|
return
|
|
else
|
|
|
|
if file_type == :makefile
|
|
|
|
line_reader.increment_line
|
|
next
|
|
end
|
|
|
|
if file_type == :parse then
|
|
|
|
full_path = File.expand_path(OS::Path.combine(line_reader.path,line))
|
|
rel_path = OS::Path.make_relative(full_path,@curr_project.path)
|
|
|
|
#
|
|
#Add this build to all platforms.
|
|
|
|
psc_path = full_path + ".psc"
|
|
|
|
if File.exists?(psc_path) then
|
|
|
|
#If a .psc file exists, add this file to the project and attach a custom build step to it.
|
|
psc_rel_path = OS::Path.make_relative(psc_path,@curr_project.path)
|
|
|
|
file_info = Info::File.new(psc_rel_path)
|
|
|
|
platformList = Info::PlatformInfo.instance()
|
|
platformList.platforms.keys.each { |platform_sym|
|
|
|
|
custom_build = Info::PscCustomBuild.new(psc_path, file_info.path, @vs2010)
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[platform_sym].config.root_node() << xml_node if xml_node != nil
|
|
}
|
|
|
|
filter.files << file_info
|
|
else
|
|
#If a .psc file does not exist, generate the parser header from the source file via a pre-build step.
|
|
@pre_build_steps[-1] = @pre_build_steps[-1] + " #{line}"
|
|
end
|
|
#############################################
|
|
|
|
@parser_output.files << Info::File.new(rel_path + "_parser.h")
|
|
else
|
|
#Use only the first word for the file name. There are cases where brackets may follow
|
|
#a filename to clarify custom steps and details to build this file.
|
|
filename = tokens[0]
|
|
full_path = File.expand_path(OS::Path.combine(line_reader.path,filename))
|
|
rel_path = OS::Path.make_relative(full_path,@curr_project.path)
|
|
|
|
if File.exists?(full_path) == false then
|
|
|
|
RageProjBuilderLoader.log.error("#{full_path} doesn't exist") unless full_path.include?("embedded_") # DW: Trying to prevent spam to crack down on more important errors at the moment.
|
|
end
|
|
|
|
file = Info::File.new(rel_path)
|
|
|
|
RageProjBuilderLoader.log.debug("add file #{rel_path}")
|
|
|
|
if file_type == :custom then
|
|
|
|
if tokens.last == "{"
|
|
import_custom_build(file, line_reader)
|
|
else
|
|
add_custom_build(file,full_path)
|
|
end
|
|
end
|
|
|
|
filter.files << file
|
|
end
|
|
end
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
end
|
|
|
|
def import_custom_command(line_reader)
|
|
|
|
line_reader.read_into_section
|
|
|
|
command = nil
|
|
|
|
while line_reader.lines_left?
|
|
|
|
line = line_reader.current_line.strip
|
|
tokens = line.split(" ")
|
|
|
|
if tokens.last == "}" then
|
|
break
|
|
end
|
|
|
|
if command == nil
|
|
command = line
|
|
else
|
|
command << "\n"
|
|
command << line
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
|
|
command
|
|
end
|
|
|
|
def import_platforms_list(line_reader)
|
|
|
|
line_reader.read_into_section
|
|
|
|
platforms = Array.new
|
|
|
|
while line_reader.lines_left?
|
|
|
|
line = line_reader.current_line.strip
|
|
tokens = line.split(" ")
|
|
|
|
if tokens.last == "}" then
|
|
break
|
|
end
|
|
|
|
if command == nil
|
|
command = line
|
|
else
|
|
command << "\n"
|
|
command << line
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
|
|
platforms
|
|
end
|
|
|
|
def import_custom_build(file_info, line_reader)
|
|
|
|
line_reader.read_into_section
|
|
|
|
command = nil
|
|
outputs = nil
|
|
dependencies = nil
|
|
description = nil
|
|
platform_str = nil
|
|
|
|
while line_reader.lines_left?
|
|
|
|
line = line_reader.current_line.strip
|
|
tokens = line.split(" ")
|
|
|
|
if tokens.size == 0
|
|
line_reader.increment_line
|
|
next
|
|
end
|
|
|
|
if tokens.last == "}" and platform_str == nil then
|
|
break
|
|
end
|
|
|
|
if tokens.last == "}" and platform_str != nil then
|
|
|
|
if command.nil?
|
|
|
|
RageProjBuilderLoader.log.error("Custom step for #{file_info} does not have a \"Command\" attribute specified. Ignoring...")
|
|
return
|
|
end
|
|
|
|
custom_build = Info::CustomBuild.new(command, outputs, dependencies, description)
|
|
create_custom_step(custom_build, file_info, platform_str)
|
|
|
|
command = nil
|
|
outputs = nil
|
|
dependencies = nil
|
|
description = nil
|
|
platform_str = nil
|
|
line_reader.increment_line
|
|
next
|
|
end
|
|
|
|
rvalue = line[(tokens[0].size+1)..-1]
|
|
if rvalue.nil?
|
|
line_reader.increment_line
|
|
next
|
|
end
|
|
|
|
rvalue = rvalue.strip! #Remove whitespace from the right-side value
|
|
|
|
case tokens[0]
|
|
|
|
when "Platform":
|
|
|
|
if tokens.last == "{"
|
|
platform_str = tokens[1].downcase
|
|
else
|
|
platform_str = nil
|
|
end
|
|
when "Command":
|
|
|
|
#Support multiple lines for commands.
|
|
if tokens.last == "{"
|
|
command = import_custom_command(line_reader)
|
|
else
|
|
command = rvalue
|
|
end
|
|
|
|
when "Outputs":
|
|
outputs = rvalue
|
|
when "Dependencies":
|
|
dependencies = rvalue
|
|
when "Description":
|
|
description = rvalue
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
|
|
if command.nil? == false
|
|
|
|
custom_build = Info::CustomBuild.new(command, outputs, dependencies, description)
|
|
create_custom_step(custom_build, file_info, nil)
|
|
end
|
|
|
|
end
|
|
|
|
def create_custom_step(custom_build, file_info, platform_str)
|
|
#If a platform has been specified, then add this custom step to only that platform.
|
|
#If no platform has been specified, add this command to all platforms.
|
|
if platform_str != nil
|
|
|
|
platform_str.downcase!
|
|
|
|
if Info::PlatformInfo.instance().is_valid(platform_str.to_sym) == false
|
|
RageProjBuilderLoader.log.error("Platform Symbol: #{platform_str} is not valid. Unable to create custom build step!\n")
|
|
return
|
|
end
|
|
|
|
Info::PlatformInfo.instance().platforms.keys.each do |platform|
|
|
|
|
if Info::PlatformInfo.instance().platforms[platform].casecmp(platform_str) == 0
|
|
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[platform].config.root_node() << xml_node
|
|
end
|
|
end
|
|
else
|
|
|
|
Info::PlatformInfo.instance().platforms.keys.each do |platform|
|
|
|
|
xml_node = custom_build.create_node()
|
|
file_info.platforms[platform].config.root_node() << xml_node
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
def import_library( line_reader, line, tokens )
|
|
|
|
section_index = line.index("{")
|
|
|
|
configurations = nil
|
|
if section_index == nil
|
|
libraries = line[(tokens[0].size+1)..-1].strip!
|
|
else
|
|
libraries = line[(tokens[0].size+1)..section_index-1].strip!
|
|
|
|
line_reader.read_into_section
|
|
configurations = import_configurations( line_reader )
|
|
end
|
|
|
|
return libraries, configurations
|
|
end
|
|
|
|
|
|
def import_configurations( line_reader )
|
|
|
|
configurations = Array.new()
|
|
|
|
while line_reader.lines_left?
|
|
|
|
line = line_reader.current_line.strip
|
|
tokens = line.split(" ")
|
|
|
|
if tokens.last == "}" then
|
|
|
|
return configurations
|
|
end
|
|
|
|
configurations << line
|
|
|
|
line_reader.increment_line
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
def import_library_directories( token, platform_sym )
|
|
|
|
return if @curr_project.platforms.has_key?(platform_sym) == false
|
|
|
|
token.split(";").each { |path|
|
|
|
|
lib_dir_node = @curr_project.platforms[platform_sym].config.find_first("librarydirectories")
|
|
|
|
if lib_dir_node == nil then
|
|
|
|
lib_dir_node = XML::Node.new("librarydirectories")
|
|
@curr_project.platforms[platform_sym].config.root_node() << lib_dir_node
|
|
end
|
|
|
|
new_lib_path = Info::LibraryDirectory.new( path )
|
|
new_library_node = new_lib_path.create_node
|
|
lib_dir_node << new_library_node
|
|
}
|
|
end
|
|
|
|
def import_include_paths( token, platform_sym )
|
|
|
|
return if @curr_project.platforms.has_key?(platform_sym) == false
|
|
|
|
#Remove duplicate include paths.
|
|
duplicate = false
|
|
|
|
token.split(";").each { |path|
|
|
|
|
current_inc_path = ScriptUtility.find_include_definition( path )
|
|
include_path_node = @curr_project.platforms[platform_sym].config.find_first("includepaths")
|
|
|
|
if include_path_node == nil then
|
|
|
|
include_path_node = XML::Node.new("includepaths")
|
|
@curr_project.platforms[platform_sym].config.root_node() << include_path_node
|
|
end
|
|
|
|
include_path_node.find("includepaths/includepath").each { |include_path|
|
|
|
|
if include_path.eql?(current_inc_path) == true
|
|
duplicate = true
|
|
break
|
|
end
|
|
}
|
|
|
|
if duplicate == false
|
|
|
|
new_inc_path = Info::IncludePath.new( current_inc_path )
|
|
new_include_node = new_inc_path.create_node
|
|
include_path_node << new_include_node
|
|
end
|
|
}
|
|
end
|
|
|
|
def add_lib( platform_sym, configurations, path )
|
|
|
|
return if @curr_project.platforms.has_key?(platform_sym) == false
|
|
|
|
libs_node = @curr_project.platforms[platform_sym].config.find_first("libs")
|
|
|
|
if libs_node == nil then
|
|
|
|
libs_node = XML::Node.new("libs")
|
|
@curr_project.platforms[platform_sym].config.root_node() << libs_node
|
|
end
|
|
|
|
lib_node = XML::Node.new("lib")
|
|
lib_node["path"] = path
|
|
|
|
if ( configurations != nil )
|
|
|
|
configurations.each do |configuration|
|
|
|
|
config_node = XML::Node.new("configuration")
|
|
config_node["name"] = configuration
|
|
|
|
lib_node << config_node
|
|
end
|
|
end
|
|
|
|
libs_node << lib_node
|
|
end
|
|
|
|
def acquire_configuration_template( line_reader )
|
|
|
|
#Set the default configuration_template to use.
|
|
globals = Pipeline::Globals.instance()
|
|
template_root = "#{globals.toolsconfig}/projbuild"
|
|
|
|
default_configuration_template = OS::Path.combine(template_root, "game_configurations.xml") if @vs2010
|
|
default_configuration_template = OS::Path.combine(template_root, "configurations.xml") unless @vs2010
|
|
configuration_template = nil
|
|
|
|
while line_reader.lines_left?
|
|
|
|
RageProjBuilderLoader.log.debug("preparse #{line_reader.filename} #{line_reader.i} ")
|
|
|
|
line = line_reader.current_line
|
|
tokens = line.split(" ")
|
|
|
|
case tokens[0]
|
|
|
|
when "Template":
|
|
|
|
configuration_template = OS::Path.combine(template_root, tokens[1]) if tokens[1] != nil
|
|
break
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
|
|
if configuration_template == nil or File.exist?(configuration_template) == false
|
|
|
|
return default_configuration_template
|
|
end
|
|
|
|
|
|
|
|
RageProjBuilderLoader.log.info("=-=-=-=-=-=-=-=-=-=- THE PROJECT T E M P L A T E IS #{configuration_template} =-=-=-=-=-=-=-=-=-==--")
|
|
|
|
return configuration_template
|
|
end
|
|
|
|
def preparse( filter, line_reader, root_node = false )
|
|
|
|
while line_reader.lines_left?
|
|
|
|
RageProjBuilderLoader.log.debug("preparse #{line_reader.filename} #{line_reader.i} ")
|
|
|
|
line = line_reader.current_line
|
|
tokens = line.split(" ")
|
|
|
|
#Comments support. Remove anything that occurs after a '#' character.
|
|
comment_index = line.index("#")
|
|
if comment_index != nil
|
|
line = line[0...comment_index]
|
|
end
|
|
|
|
case tokens[0]
|
|
|
|
when "Project":
|
|
@curr_project.name = tokens[1] if @curr_project.name == nil and root_node == true
|
|
when "RootDirectory":
|
|
line_reader.filepath = tokens[1]
|
|
when "ForceInclude":
|
|
|
|
tokens[1].split(";").each { |path|
|
|
|
|
@force_includes << path
|
|
}
|
|
when "PrecompiledHeader":
|
|
RageProjBuilderLoader.log.debug("tokens[1] #{tokens[1]}")
|
|
@precompiled_header = tokens[1]
|
|
when "EmbeddedLibAll":
|
|
|
|
libraries, configurations = import_library(line_reader, line, tokens)
|
|
|
|
@curr_project.platforms.keys.each do |platform_sym|
|
|
|
|
add_lib(platform_sym, configurations, libraries)
|
|
end
|
|
|
|
when "EmbeddedLibWin32":
|
|
|
|
libraries, configurations = import_library(line_reader, line, tokens)
|
|
add_lib(:win32, configurations, libraries)
|
|
|
|
when "EmbeddedLibWin64":
|
|
|
|
libraries, configurations = import_library(line_reader, line, tokens)
|
|
add_lib(:win64, configurations, libraries)
|
|
when "EmbeddedLibXenon":
|
|
|
|
libraries, configurations = import_library(line_reader, line, tokens)
|
|
add_lib(:xbox360, configurations, libraries)
|
|
when "EmbeddedLibPsn":
|
|
|
|
libraries, configurations = import_library(line_reader, line, tokens)
|
|
|
|
add_lib(:ps3, configurations, libraries)
|
|
|
|
when "LibraryDirectory":
|
|
#Include this path in all available platforms.
|
|
@curr_project.platforms.keys.each do |platform_sym|
|
|
|
|
import_library_directories(tokens[1], platform_sym)
|
|
end
|
|
when "LibraryDirectoryWin32":
|
|
import_library_directories(tokens[1], :win32)
|
|
when "LibraryDirectoryWin64":
|
|
import_library_directories(tokens[1], :win64)
|
|
when "LibraryDirectoryPsn":
|
|
import_library_directories(tokens[1], :ps3)
|
|
when "LibraryDirectoryXenon":
|
|
import_library_directories(tokens[1], :xbox360)
|
|
|
|
when "IncludePath":
|
|
|
|
#Include this path in all available platforms.
|
|
@curr_project.platforms.keys.each do |platform_sym|
|
|
|
|
import_include_paths(tokens[1], platform_sym)
|
|
end
|
|
|
|
when "IncludePathWin32":
|
|
import_include_paths(tokens[1], :win32)
|
|
when "IncludePathWin64":
|
|
import_include_paths(tokens[1], :win64)
|
|
when "IncludePathPsn":
|
|
import_include_paths(tokens[1], :ps3)
|
|
when "IncludePathXenon":
|
|
import_include_paths(tokens[1], :xbox360)
|
|
when "ProjectReference"
|
|
|
|
#Convert these project references into an absolute path with no environment variables.
|
|
project_reference_path = ScriptUtility.convert_paths_in_line(tokens[1])
|
|
project_reference_path = File.expand_path(project_reference_path) if project_reference_path.index(":") != nil
|
|
|
|
@project_references << project_reference_path
|
|
when "Define":
|
|
define_var = line[(tokens[0].size+1)..-1].strip!
|
|
@defines[define_var] = true
|
|
when "Directory":
|
|
line_reader.read_into_section
|
|
import_directories(line_reader,filter)
|
|
when "Files":
|
|
line_reader.read_into_section
|
|
store_path = line_reader.path
|
|
#puts("#{line_reader.path} #{line_reader.filepath}")
|
|
line_reader.path = OS::Path.combine(line_reader.path,line_reader.filepath)
|
|
import_files(:files,filter,line_reader)
|
|
line_reader.path = store_path
|
|
when "Custom":
|
|
line_reader.read_into_section
|
|
import_files(:custom,filter,line_reader)
|
|
when "Embedded":
|
|
line_reader.read_into_section
|
|
import_files(:embedded,filter,line_reader)
|
|
when "Parse":
|
|
do_parse(filter,line_reader)
|
|
when "CustomBuildStep":
|
|
RageProjBuilderLoader.log.error("CustomBuildStep not handled")
|
|
when "ConfigurationType"
|
|
@configuration_type = tokens[1]
|
|
when "OutputFileName"
|
|
@output_file_name = tokens[1]
|
|
when "WarningLevel"
|
|
@warning_level = tokens[1]
|
|
when "WarningsAsErrors"
|
|
@warnings_as_errors = tokens[1]
|
|
when "ModuleDefinitionFile"
|
|
@module_definition_file = tokens[1]
|
|
when "XboxTitleId"
|
|
@xbox_title_id = tokens[1]
|
|
when "XboxSpaPath"
|
|
@xbox_spa_path = tokens[1]
|
|
when "{"
|
|
RageProjBuilderLoader.log.error("Invalid \"{\" token found! All opening brackets must be on the same line as the keyword. (e.g. EmbeddedLibPsn <lib name> { )")
|
|
end
|
|
|
|
line_reader.increment_line
|
|
end
|
|
end
|
|
end
|
|
|
|
class RageProjBuilder
|
|
|
|
@@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 )
|
|
|
|
loader = RageProjBuilderLoader.new(@vs2010)
|
|
return loader.import(path, options);
|
|
end
|
|
|
|
def initialize(vs2010 = false)
|
|
@vs2010 = vs2010
|
|
end
|
|
end
|
|
|
|
end #module ProjBuild
|
|
|
|
end #module Pipeline
|