# encoding: utf-8 require 'rake' require 'rake/common/chdirtask' require 'rake/common/logger' require 'rake/delphi/envvariables' require 'rake/delphi/resources' require 'rake/delphi/tool' require 'rake/helpers/rake' require 'rake/helpers/raketask' module Rake module Delphi class Dcc32Tool < CustomDelphiTool def self.toolName 'bin/dcc32.exe' end def delphidir @@delphidir end def delphilib ENV['BDSLIB'] end def readLibraryPaths(platform) warn "WARNING! You are using Delphi XE or above but no platform defined!" if ENV['DELPHI_VERSION'].to_i >= 14 && ! platform platform = platform.to_s != '' ? '\\' + platform : '' # platform not used for old Delphis 'SearchPath' libpaths = self.class.readUserOption('Library' + platform, 'Search Path', self.version).split(';') \ | self.class.readUserOption('Library', 'SearchPath', self.version).split(';') Logger.trace(Logger::TRACE, libpaths) dev = EnvVariables.new(self.class.rootForVersion(self.version) + '\Environment Variables', self.delphidir) libpaths.map! do |lp| unless lp.to_s.empty? lp = dev.expand(lp) end lp end Logger.trace(Logger::TRACE, libpaths) return libpaths end end class Dcc32Task < Rake::Task attr_accessor :systempath, :mainicon, :_source, :exeoutput, :bin private @@symbols = [:quiet, :assertions, :build, :optimization, :debug, :defines, :debuginfo, :localsymbols, :console, :warnings, :hints, :altercfg, :includepaths, :writeableconst, :map, :dcuoutput, :bploutput, :aliases, :platform, :namespaces, :dcpoutput, :dcu, :uselibrarypath, :uselibrarypath, :usecfg] public @@symbols.map do |sym| attr_accessor sym unless method_defined?(sym) end def initialize(name, application) super initvars @arg_names = [:verbose] @rc_template_task = application.define_task(RCTemplateTask, shortname + ':rc:template') @rc_task = application.define_task(RCTask, shortname + ':rc') enhance([@rc_template_task, @rc_task]) @platform = nil @dcc32Tool = Dcc32Tool.new end # used in tests def reenable # recreate Dcc32Tool to reinitialize paths to tool @dcc32Tool = Dcc32Tool.new(true) super end def versionInfoClass @dcc32Tool.versionInfoClass end private def initvars @exeoutput = nil @@symbols.map do |sym| instance_variable_set("@#{sym.to_s}", nil) end end def delphilibs return [@dcc32Tool.delphilib] | @dcc32Tool.readLibraryPaths(@platform) end def platform=(value) @platform = value Logger.trace(Logger::DEBUG, 'PLATFORM set: ' + value) ENV['PLATFORM'] = @platform # for XE and above set default aliases and namespaces if ENV['DELPHI_VERSION'].to_i >= 14 @aliases = 'Generics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE' @namespaces = 'Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;System;Xml;Data;Datasnap;Web;Soap' Logger.trace(Logger::TRACE, 'Aliases and namespaces are set for Delphi XE') end end def _paths(ppaths) ppaths.map! do |p| a = [] ['U', 'I', 'R', 'O'].each do |s| a << Rake.quotepath("-#{s}", p) end a end # unique paths only ppaths.flatten!.uniq! ppaths end def implicitpaths ipaths = ['.', '..'] ipaths |= delphilibs if @uselibrarypath _paths(ipaths) end def paths @includepaths ||= [] _paths(@includepaths) end def debug? return @debug ? '-$D+ -$L+ -$YD -$C+ -$Q+ -$R+ -$O- -GD' : '' end def build? return @build ? '-B' : '-M' end def warnings? return @warnings ? '-W-' : '-W+' end def hints? return @hints ? '-H-' : '-H+' end def quiet? return @quiet ? '-Q' : '' end def aliases return @aliases ? Rake.quotepath('-A', @aliases) : '' end def namespaces return @namespaces ? Rake.quotepath('-NS', @namespaces) : '' end def exeoutput return @exeoutput || @bin end def dcuoutput return @dcuoutput || @dcu || @_source.pathmap('%d%sdcu') end def map # segments -> -GS # publics -> -GP # detailed -> -GD return unless @map segments = @map.to_s[0..0].upcase return '-G' + segments end def alldebuginfo return @debuginfo ? '-$D+ -$L+ -$YD' : '-$D- -$L- -$Y-' end def outputs os = [] os << Rake.quotepath('-E', exeoutput) os << Rake.quotepath('-N', dcuoutput) os << Rake.quotepath('-LE', @bploutput) return os end def _source return Rake.quotepath('', @_source) end def defines '-D' + @defines if @defines end def writeableconst return '-$J' + (@writeableconst ? '+' : '-') end def build_args args = [] args << build? << warnings? << hints? << quiet? << debug? << alldebuginfo << map args << defines << writeableconst << aliases << namespaces args << _source << outputs << implicitpaths args.flatten end public def init(properties) Logger.trace(Logger::TRACE, properties) properties.map do |key, value| begin send("#{key}=", value) rescue NoMethodError instance_variable_set("@#{key}", value) end end @_source = properties[:projectfile].pathmap('%X.dpr') src = @_source.gsub('\\', '/') dcu = src.pathmap('%d%sdcu') # make sure to create dir for output dcu # for now default is /dcu directory dcu enhance([dcu]) # mainicon is usually requested by RCTemplate @mainicon ||= Rake.quotepath('', src.pathmap('%X.ico')) @rc_template_task.output = src @rc_template_task[:version] = properties[:version] @rc_template_task[:releaseCandidate] = properties[:releaseCandidate] @rc_task.input = src @rc_task.is_rc = properties[:releaseCandidate] @rc_task.mainicon_path = @mainicon return unless properties[:resources_additional] res_add = properties[:resources_additional] if res_add.kind_of?(String) res_add = res_add.split(';') end c = 0 res_add.each do |res| if res.kind_of?(Symbol) rc_task_add = res else c = c.next rc_task_add = application.define_task(RCTask, shortname + ':rc:add' + c.to_s) rc_task_add.input = src.pathmap('%d%s') + res end enhance([rc_task_add]) end end def init_libs(libs = nil) unless libs # call parent to find libs application[name.gsub(/:dcc32$/, '')].init_libs else # called from parent # set libs @includepaths = libs end end def execute(opts=nil) super @dcc32Tool.class.checkToolFailure(@dcc32Tool.toolpath) fail "Could not find #{_source} to compile" unless @_source && File.exists?(@_source) init_libs args = build_args # on cygwin $D is assumed as shell var # so escape $ args.map! { |a| a.gsub('$', '\$') if a.kind_of?(String) } unless application.windows? args.compact! cmd = Rake.quotepath('', @dcc32Tool.toolpath) cmd << ([''] | args).join(' ') ChDir.new(self, File.dirname(@_source)) do |dir| RakeFileUtils.verbose(Logger.debug?) do begin unless @usecfg cfg = @systempath.pathmap('%X.cfg') bak_cfg = @systempath.pathmap('%X.rake.cfg') if File.exists?(cfg) mv cfg, bak_cfg else warn "WARNING! Config #{cfg} is absent!" end if @altercfg cp @altercfg, cfg end # on Windows there is some limit on command line parameters length # so we just append path parameters to config file File.open(cfg, 'a+') do |f| paths.each do |p| f.write(p + "\n") end end end sh cmd ensure unless @usecfg begin cp cfg, cfg + '.1' if trace? ensure mv bak_cfg, cfg if File.exists?(bak_cfg) end end end end end puts '' # make one empty string to separate from further lines end end end end