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

279 lines
8.9 KiB
Ruby
Executable File

#
# File:: projbuild.rb
#
# Pipeline::Cross platform generic project file builder system that supports
# output to multiple target compilers.
#
# Author:: Greg Smith <greg@rockstarnorth.com>
# Date:: 15 January 2010
#
#
#-----------------------------------------------------------------------------
# Uses
#-----------------------------------------------------------------------------
require "pipeline/coding/projbuild/generators/csharp"
require "pipeline/coding/projbuild/generators/ragegen"
require "pipeline/coding/projbuild/generators/rageprojbuilder"
require "pipeline/coding/projbuild/generators/vs2005"
require "pipeline/coding/projbuild/generators/vs2008"
require "pipeline/coding/projbuild/generators/vs2010"
require "pipeline/coding/projbuild/generators/shadermakefile"
require "pipeline/coding/projbuild/generators/qaitems"
require "pipeline/coding/projbuild/generators/internal"
require "pipeline/coding/projbuild/unity_build"
require "pipeline/os/path"
require "pipeline/gui/exception_dialog"
require "pipeline/log/log"
#-----------------------------------------------------------------------------
# Implementation
#-----------------------------------------------------------------------------
module Pipeline
module ProjBuild
class ProjBuilder
attr_accessor :unity_build
attr_accessor :vs2010
@@log = nil
def ProjBuilder.log
@@log = Log.new( 'projbuild' ) if @@log == nil
@@log
end
def initialize( vs2010 = false )
@vs2010 = vs2010 # sadly this code needs to specialise for VS2010, IIRC for PSCCustom jobs, under VS2010 the interal macros differ.
OS::Path.set_downcase_on_normalise(false)
@generators = Hash.new()
@generators[:csharp] = CSharpGenerator.new()
@generators[:vs2005] = VS2005Generator.new()
@generators[:vs2008] = VS2008Generator.new()
@generators[:vs2010] = VS2010Generator.new()
@generators[:internal] = ProjBuildGenerator.new()
@generators[:ragegen] = RageGenGenerator.new()
@generators[:rageprojbuilder] = RageProjBuilder.new(@vs2010)
@generators[:shadermakefile] = ShaderMakefileGenerator.new()
@generators[:qaitems] = QAItemsGenerator.new()
@config = Pipeline::Config.instance
@config.project.load_config
@p4 = SCM::Perforce.new()
@p4.port = @config.sc_server
@p4.client = @config.sc_workspace
@p4.user = @config.sc_username
@p4.connect()
@projects = Array.new
end
#possible extra options:
#single file, or recursively
#look for related files (pass _2008, ask it to look for _2008 variants etc)
def import( path, forcetype = nil, options = nil )
begin
initialize(@vs2010) # DW - what on earth is this all about?
# DW : sigh it needs set here due to design flaws with the project builder - since at import we need to know if a unity build is enabled due to 2010 vcxproj project references.
if (options[:unity_build_enabled])
@generators.values.each { |g| g.set_unity_build_filenames( true ) }
else
@generators.values.each { |g| g.set_unity_build_filenames( false ) }
end
#ProjBuildData::instance().reset()
GC.enable()
GC.start()
GC.disable()
path = OS::Path.normalise(path)
#ProjBuilder::log.info("Importing #{path}...")
#ProjBuilder::log.info("Forcetype: #{forcetype.to_s}") if forcetype != nil
#Does the file exist?
#raise Exception.new("#{path} doesn't exist!") if File.exists?(path) == false
if forcetype == nil then
#pass it to each generator
@generators.values.each { |g|
ret, @projects = g.import(path, options)
ProjBuilder::log.info("..generator import returned false") if ret == false
return false if ret == false
if @projects != nil then
@projects.each do |project|
ProjBuildData::instance().projects[project.guid] = project
end
end
return true
}
else
#ProjBuilder::log.info("..generator import path #{path} options #{options}")
ret, @projects = @generators[forcetype].import(path, options)
ProjBuilder::log.info("@projects.length is #{@projects.length}") if @projects and @projects.length <= 0
return false if ret == false
ProjBuilder::log.info("..generator import returned false") if ret == false
if @projects != nil then
@projects.each do |project|
ProjBuildData::instance().projects[project.guid] = project
end
end
return true
end
return false
rescue Exception => ex
puts "Unhandled exception: #{ex.message}"
puts ex.backtrace.join( "\n" )
#log.error( ex, 'Unhandled exception in projbuild' )
GUI::ExceptionDialog::show_dialog( ex, 'Unhandled exception in projbuild' )
ensure
#LogSystem::instance( ).shutdown( )
end
end
def export( path, forcetype = nil, options = nil )
begin
retval = false
GC.enable()
path = OS::Path.normalise(path)
#ProjBuilder::log.info("exporting(projbuild.rb export) #{path}")
ProjBuilder::log.debug("forcetype #{forcetype.to_s}") if forcetype != nil
proj_build = ProjBuildData::instance()
#ProjBuilder::log.info("No projects to export - did the import succeed?") if @projects == nil
return true if @projects == nil
if @projects.size < 1
ProjBuilder::log.info("Generator did not create any projects to export ( projbuild.rb)!\n")
return false
end
ProjBuilder::log.info("About to export #{@projects.size} projects") if @projects.size > 1
@projects.each do |project|
if project == nil
#HACK: In some generators, such as the RageGen solution generator, we can not rely on the export
#call of the generator to do our work. For now, gracefully handle the instances were project
#is nil so we do not crash.
ProjBuildData::instance().reset()
return true
end
#The output path will be the directory of the 'path' object, plus the name of the project.
path = OS::Path.combine(File.dirname(path), project.name)
#TODO: Determine if we can use the project.path variable...
unity_setup = "%RS_TOOLSROOT%/etc/project.xml/project/branches/branch/codeconfigs/codeconfig/unity_build/@enabled"
if (not options[:unity_build_enabled].nil?) and options[:unity_build_enabled]
#path = "#{path}_unity"
ProjBuilder::log.info("Unity build enabled via #{unity_setup} for #{path}")
unity_config_file = "#{project.name}.unity"
ret = unity_process( unity_config_file, project )
if ret == false or ret.nil?
ProjBuilder::log.warn("\n\nWARNING : *** Unity build is enabled but a unity build failed to run ok - possibly no unity file - this project will not be built ***\n\n")
return false
end
else
ProjBuilder::log.info("Unity build disabled via #{unity_setup}.")
end
# filenames will be built with _unity in them if unity build is enabled via options,
# but it may not have built a unity configured project file as it can still be disabled
# via a missing .unity file, or disabled in the .unity file, hence the name 'unity_build_filenames'
if (options[:unity_build_enabled])
#ProjBuilder::log.info("Setting all generators (#{@generators.length}) to have unity filenames enabled.")
@generators.values.each { |g| g.set_unity_build_filenames( true ) }
else
#ProjBuilder::log.info("Setting all generators (#{@generators.length}) to have unity filenames DISABLED.")
@generators.values.each { |g| g.set_unity_build_filenames( false ) }
end
do_checkout = false
# Do not test for the file's attributes as writable.
# All .sln and .vcproj files are marked writable on client.
if forcetype == nil then
ProjBuilder::log.info("Forcetype is not set - whatever that achieves?")
#pass it to each generator
@generators.values.each { |g|
if g.export(path, project, options) then
retval = true
break
end
}
else
#ProjBuilder::log.info("Forcetype is set #{forcetype} - whatever that achieves?")
#ProjBuilder::log.info("class #{@generators[forcetype].class}")
retval = @generators[forcetype].export(path, project, options)
end
if do_checkout then
@p4.run_revert("-a",path)
end
if retval == false then
ProjBuilder::log.debug("Did not export #{path}!")
break;
end
end
ProjBuildData::instance().reset()
return retval
rescue Exception => ex
puts "Unhandled exception: #{ex.message}"
puts ex.backtrace.join( "\n" )
ProjBuilder::log.error( ex, 'Unhandled exception in projbuild' )
GUI::ExceptionDialog::show_dialog( ex, 'Unhandled exception in projbuild' )
ensure
LogSystem::instance( ).shutdown( )
end
end
end
end
end