#============================================================================== # Rules for creating MSVC project files. # Copyright (C) 2004 by Eric Sunshine # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public # License for more details. # # You should have received a copy of the GNU Library General Public License # along with this library; if not, write to the Free Software Foundation, # Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #============================================================================== # # During a project file synthesis run, the property name 'projgen' in the # container 'build' will be given a value describing which type of project # files are being generated. For MSVC project files, the value of the 'projgen' # property will be "msvc". When project file synthesis supports multiple tool # versions, the 'projgen_version' property will have a value indicating the # version of the tool for which project files are being created. For instance, # when generating MSVC7 project files, 'projgen' will be set to "msvc" and # 'projgen_version' will have the value "7". # # Jamfiles throughout the project, if they need to alter their behavior (for # one reason or another), can invoke the Property rule to determine whether # project files are being synthesized. For example, to learn if project file # synthesis is active: # # if [ Property build : projgen ] { ... do something ... } # # To take action if only a particular type of project file is being generated # (i.e. "msvc"): # # if [ Property build : projgen ] = msvc { ... do something ... } # #============================================================================== MSVCGEN_SUPPORTED_VERSIONS = 6 7 71 8 sn71 xenon8 ; MSVCGEN_BUILD_ROOT ?= [ ConcatDirs $(BUILDTOP) out ] ; MSVCGEN_BUILD_TEMP ?= [ ConcatDirs $(MSVCGEN_BUILD_ROOT) msvcgen ] ; #------------------------------------------------------------------------------ # Public rule stubs. May be implemented by msvcgen phase 1 or phase 2 or both. ## MsvcGenConfig variable [ : value ] ## Specify additional configuration information to augment the msvcgen ## environment. The Jam variable named by 'variable' is set to 'value' for ## the msvcgen run. If 'value' is omitted, then 'variable' is cleared. ## Invocations of MsvcGenConfig are cumulative, so variable/value tuples can ## be provided incrementally. It is legal to use this rule in conjunction ## with MsvcGenConfigFile; they are not mutually exclusive. ## ## The most common reason to invoke this rule is to provide MSVC-specific ## fallback values for the library checks typically performed by an Autoconf ## configure script, which the Jamfiles reference via the ExternalLibs rule. ## Such fallbacks consist of variables named TAG.CFLAGS, TAG.LFLAGS, and ## TAG.LIBS, where TAG represents the library's identifier exported by the ## configure script. Because project generation allows for finer-grained ## control, you can also optionally set the variables TAG.DEFINES, ## TAG.INCDIRS, and TAG.LIBDIRS. TAG.DEFINES is a set of tokens of the form ## "key" or "key=value". For instance, to provide MSVC-specific fallback ## values for the FreeType2 library, which the configure script might ## identify as FT2, you can define variables named FT2.CFLAGS, FT2.LFLAGS, ## FT2.LIBS, FT2.DEFINES, FT2.INCDIRS, and FT2.LIBDIRS. The msvcgen process ## will consult these variables when it encounters invocations of the ## ExternalLibs rule, and apply the overrides to the generated project files. ## If yours is a multi-platform project which conditionally defines ## Application, Plugin, and Library targets based upon the platform, then you ## should also define whatever additional variables or properties are needed ## to ensure that your project's Jamfiles invoke the Application, Plugin, and ## Library rules for modules suitable for Windows, and that they do not ## invoke those rules for modules specific to other platforms. rule MsvcGenConfig { MsvcGenConfig1 $(1) : $(2) ; } rule MsvcGenConfig1 { } ## MsvcGenConfigFile file ## Similar to MsvcGenConfig, except that the configuration is provided via a ## file containing Jam statements. In the common case, the file will contain ## a series of simple Jam variable assignment statements. May be invoked ## multiple times to specify additional configuration files. It is legal to ## use this rule in conjunction with MsvcGenConfig; they are not mutually ## exclusive. rule MsvcGenConfigFile { MsvcGenConfigFile1 $(1) : $(2) ; } rule MsvcGenConfigFile1 { } ## MsvcGenVariable variable [ : value ] ## Define a variable for direct interpolation into msvcgen template files. ## 'variable' is the name of the variable to define. 'value' is the value ## which should be assigned to 'variable'. If 'value' is omitted, then ## 'variable' is defined as the null (empty) string. You may invoke this ## rule multiple times to define any number of interpolation variables. You ## may also invoke it multiple times for the same variable name to give the ## variable multiple values. In the template file, reference the variable as ## `[% variable.0 %]' to retrieve the first element, `[% variable.1 %]' to ## retrieve the second, and so on. Even if you have only invoked this rule ## once for a variable, you must still reference it in the template as ## `[% variable.0 %]'. If the variable has multiple values, then it is common ## to reference it in the template via a FOREACH loop, as in ## `[% FOREACH v IN variable %]'. rule MsvcGenVariable { MsvcGenVariable1 $(1) : $(2) ; } rule MsvcGenVariable1 { } ## MsvcGenWorkspace name [ : accepts [ : rejects ]] ## Specify the name of a workspace which the 'msvcgen' target should create. ## The generated workspace file name will be prefixed by "wks". By default, ## a workspace contains all projects resulting from invocations of the ## Application, Plugin, Library, and CompileGroups rules. It is possible to ## restrict the projects placed into the workspace by providing the optional ## 'accepts' and/or 'rejects'. These are lists of Perl regular expressions ## matched against the project names. (Project names are composed of "app", ## "plg", "lib", and "grp" prepended to the target name given to the ## Application, Plugin, Library, and CompileGroups rules, respectively.) ## Reject patterns take precedence over accept patterns. This rule must be ## invoked before any invocations of Application, Plugin, Library, or ## CompileGroups. You may invoke this rule multiple times to produce ## multiple workspaces, but you must invoke it at least once in order for the ## 'msvcgen' target to produce any output. rule MsvcGenWorkspace { MsvcGenWorkspace1 $(1) : $(2) : $(3) ; } rule MsvcGenWorkspace1 { } ## MsvcGenSubDir dircomponents [ : version ] ## Invoke this rule with the location of the project file directory as a ## whitepace-delimited set of tokens, much as you would the SubDir rule. ## This information is used in two ways. (1) The directory structure for the ## generated files will be duplicated under $(MSVCGEN_BUILD_ROOT). For ## instance, if your project files are at "$(TOP)/proj/msvc", then the ## generated files will be deposited at "$(MSVCGEN_BUILD_ROOT)/proj/msvc". ## (2) The depth of the directory indicated by 'dircomponents' will be taken ## into account when generating references to resources in your project tree. ## For example, if your project files reside at "$(TOP)/proj/msvc", and you ## have set "$(TOP)/resources/game.ico" as the application icon with the ## ApplicationIconDefault or ApplicationIcon rule, then msvcgen will know ## that game.ico can be found relative to the project file directory via the ## path "../../resources/game.ico". If 'version' is specified, then ## 'dircomponents' applies to generated files for that version of MSVC only. ## If 'version' is not specified, then the path will be composed of ## 'dircomponents' and the version number. For instance, if 'dircomponents' ## is "$(TOP)/proj/msvc" and 'version' was not provided, then it will be ## assumed that MSVC7 project files should reside at $(TOP)/proj/msvc7". You ## must invoke this rule at least once to ensure that 'msvcgen' targets are ## made available for user invocation. rule MsvcGenSubDir { msvcgen_path_version MsvcGenSubDir1 : $(1) : $(2) ; } rule MsvcGenSubDir1 { } ## MsvcGenTemplateDir dircomponents ## Invoke this rule with the location of the msvcgen template directory as a ## whitepace-delimited set of tokens. rule MsvcGenTemplateDir { MsvcGenTemplateDir1 $(1) ; } rule MsvcGenTemplateDir1 { } ## MsvcExternalLibrary target [ : libs [ : mode ]] ## Invoke this rule to link 'target' with one or more MSVC-specific external ## libraries. For example, 'libs' might be "wsock32.lib". 'mode' should be ## "release" or "debug". If 'mode' is omitted, then 'libs' is used for ## release and debug. rule MsvcExternalLibrary { MsvcExternalLibrary1 $(1) : $(2) : $(3) ; } rule MsvcExternalLibrary1 { } ## MsvcDefine target [ : key [ : value [ : mode ]]] ## Invoke this rule to define an MSVC-specific preprocessor macro 'key' ## having 'value' for 'target'. 'mode' should be "release" or "debug". If ## 'mode' is omitted, then 'key/value' is used for release and debug. rule MsvcDefine { MsvcDefine1 $(1) : $(2) : $(3) : $(4) ; } rule MsvcDefine1 { } ## MsvcIncDirs target : directories [ : mode ] ## Invoke this rule to define an MSVC-specific additional include directories. ## 'mode' should be "release" or "debug". If 'mode' is omitted, then ## 'directories' is used for release and debug. rule MsvcIncDirs { MsvcIncDirs1 $(1) : $(2) : $(3) ; } rule MsvcIncDirs1 { } ## MsvcCFlags target [ : cflags [ : mode ]] ## Invoke this rule to set additional MSVC-specific compiler flags for ## 'target'. 'mode' should be "release" or "debug". If 'mode' is omitted, ## then 'cflags' is used for release and debug. rule MsvcCFlags { MsvcCFlags1 $(1) : $(2) : $(3) ; } rule MsvcCFlags1 { } ## MsvcLFlags target [ : lflags [ : mode ]] ## Invoke this rule to set additional MSVC-specific linker flags for ## 'target'. 'mode' should be "release" or "debug". If 'mode' is omitted, ## then 'lflags' is used for release and debug. rule MsvcLFlags { MsvcLFlags1 $(1) : $(2) : $(3) ; } rule MsvcLFlags1 { } ## MsvcGenName target : name ## Assign an MSVC project name to 'target'. Normally, the project name is ## 'target' with a prefix of "app", "grp", "lib", "plg", or "wks", depending ## upon the target's type. The MsvcGenName rule allows you to override the ## default name. This rule must be invoked prior to the Application, ## Library, Plugin, or MsvcGenWorkspace rule for 'target' in order for 'name' ## to be accepted. As an alternative to invoking this rule, if you wish to ## change the default prefixes used by all targets you can use the MsvcConfig ## rule to set the MSVC.PREFIX.appcon, MSVC.PREFIX.appgui, MSVC.PREFIX.group, ## MSVC.PREFIX.library, MSVC.PREFIX.plugin, and MSVC.PREFIX.workspace ## variables to whatever values you like. rule MsvcGenName { MsvcGenName1 $(1) : $(2) ; } rule MsvcGenName1 { } #------------------------------------------------------------------------------ # Private utility rules. Common to all phases. ## msvcgen_path_version rule : dircomponents [ : version ] ## If 'version' is provided, invoke 'rule' once with 'dircomponents' and ## 'version' as arguments. If 'version' is not provided, invoke 'rule' once ## per supported MSVC version with 'dircomponents' augmented so that ## 'version' is appended to the very last element of 'dircomponents'. For ## example, if 'version' is omitted, and 'dircomponents' is "TOP proj msvc", ## then 'rule' will be invoked as "rule TOP proj msvc6 : 6", then "rule TOP ## proj msvc7 : 7", etc. rule msvcgen_path_version { local subrule = $(1) ; local path = $(2) ; local version = $(3) ; if $(version) { msvcgen_version_check $(version) ; $(subrule) $(path) : $(version) ; } else { local v ; for v in $(MSVCGEN_SUPPORTED_VERSIONS) { local p = [ FReverse $(path) ] ; $(subrule) [ FReverse $(p[1])$(v) $(p[2-]) ] : $(v) ; } } } rule msvcgen_resolve_dir { return $($(<[1])) $(<[2-]) ; } rule msvcgen_target_dir { return [ ConcatDirs $(MSVCGEN_BUILD_ROOT) $(<[2-]) ] ; } rule msvcgen_build_dir { return [ ConcatDirs $(MSVCGEN_BUILD_TEMP) build$(<) ] ; } rule msvcgen_work_dir { return [ ConcatDirs $(MSVCGEN_BUILD_TEMP) temp$(<) ] ; } rule msvcgen_template_dir { return [ ConcatDirs [ msvcgen_resolve_dir $(<) ] ] ; } rule msvcgen_version_check { if $(<) != common && ! [ IsElem $(<) : $(MSVCGEN_SUPPORTED_VERSIONS) ] { exit "Error: `$(<)' is not a supported msvcgen version number; valid " "numbers are:" $(MSVCGEN_SUPPORTED_VERSIONS) ; } } rule MsvcRmTemps { if $(MSVCGEN_KEEPTEMPS) != yes { RmTemps $(<) : $(>) ; } } #------------------------------------------------------------------------------ # Phase 1 if ! $(DO_MSVCGEN) { JAM ?= jam ; MSVCGEN_JAMOPTIONS ?= ; MSVCGEN_TTREEOPTIONS ?= ; MSVCGEN_SILENT ?= no ; MSVCGEN_VERBOSE ?= no ; MSVCGEN_KEEPTEMPS ?= no ; if $(MSVCGEN_SILENT) = yes { MSVCGEN_JAMOPTIONS += -d0 ; } else { MSVCGEN_TTREEOPTIONS += "--verbose" ; if $(MSVCGEN_VERBOSE) = yes { if $(JAMVERSION) <= 2.4 { MSVCGEN_JAMOPTIONS += -d+2 ; } else { MSVCGEN_JAMOPTIONS += -d5 ; } } } if $(MSVCGEN_KEEPTEMPS) = yes { MSVCGEN_JAMOPTIONS += "-sMSVCGEN_KEEPTEMPS=yes" ; } ## MsvcGenConfigFile file ## (See documentation above.) rule MsvcGenConfigFile1 { MSVCGEN_CONFIG_FILES += $(<) ; } ## MsvcGenSubDir dircomponents [ : version ] ## (See documentation above.) rule MsvcGenSubDir1 { local path = $(1) ; local version = $(2) ; if ! [ Property msvcgen : pathset$(version) ] { SetProperty msvcgen : pathset$(version) ; MsvcGenTarget $(path) : $(version) ; } else { Echo "Warning: MsvcGenSubDir already invoked for version $(version)" ; } } ## MsvcGenTarget dircomponents : version ## Create pseudo-targets for building and removing project files for the ## specified version of MSVC. 'dircomponents' is interpreted as described ## for the MsvcGenSubDir rule. Also populates the list MSVCGEN_TARGETS with ## names of the targets. Clients which need to perform some pre-processing ## prior to the actual msvcgen run may set the targets in this list to depend ## upon client-supplied targets. rule MsvcGenTarget { local path = $(1) ; local version = $(2) ; if $(version) = common { CleanDir msvccommonclean : [ msvcgen_target_dir $(path) ] ; Depends msvcclean : msvccommonclean ; } else { MsvcGenUmbrella ; Always msvc$(version)gen ; NotFile msvc$(version)gen ; MSVC_VERSION on msvc$(version)gen = $(version) ; MsvcGen msvc$(version)gen ; Depends msvcgen : msvc$(version)gen ; Help msvc$(version)gen : "Create MSVC$(version) project files" ; MSVCGEN_TARGETS += msvc$(version)gen ; local commonworkdir = [ msvcgen_work_dir common ] ; CleanDir msvc$(version)clean : [ msvcgen_target_dir $(path) ] [ msvcgen_build_dir $(version) ] [ msvcgen_work_dir $(version) ] $(commonworkdir) ; Depends msvcclean : msvc$(version)clean ; Help msvc$(version)clean : "Remove built MSVC$(version) project files" ; } } actions MsvcGen bind MSVCGEN_CONFIG_FILES { $(JAM) $(MSVCGEN_JAMOPTIONS) \ -sDO_MSVCGEN=yes \ -sMSVC_VERSION=$(MSVC_VERSION) \ -sMSVCGEN_TTREEOPTIONS='$(MSVCGEN_TTREEOPTIONS)' \ -sMSVCGEN_CONFIG_FILES='$(MSVCGEN_CONFIG_FILES)' \ -sTARGET.OS=WIN32 \ msvcgen } ## MsvcGenUmbrella ## Create pseudo-targets for building and removing project files for all ## version of MSVC. rule MsvcGenUmbrella { if ! [ Property msvcgen : umbrella ] { SetProperty msvcgen : umbrella ; Always msvcgen ; NotFile msvcgen ; Help msvcgen : "Create MSVC project files (all versions)" ; Always msvcclean ; NotFile msvcclean ; Help msvcclean : "Remove built MSVC project files (all versions)" ; CleanDir msvcclean : $(MSVCGEN_BUILD_TEMP) ; Depends clean : msvcclean ; } } } else { #------------------------------------------------------------------------------ # Phase 2 if $(MSVCGEN_CONFIG_FILES) { local f ; for f in $(MSVCGEN_CONFIG_FILES) { include $(f) ; } } if $(TTREE) { PERL ?= perl ; RUN_TTREE ?= $(PERL) "\"$(TTREE)\"" ; } else { TTREE ?= ttree ; RUN_TTREE ?= $(TTREE) ; } # Implementation note: The --strip-root directives are order-sensitive when the # build directory is the same as the source directory, in which case TOP is "." # and MSVCGEN_BUILD_ROOT is "./out". If TOP incorrectly appeared first, then # it would invalidate the following --strip-root option since TOP is a prefix # of MSVCGEN_BUILD_ROOT. MSVCGEN_STRIP_ROOT = $(MSVCGEN_BUILD_ROOT)/ $(TOP)/ ; # When generating the icon file .rc, we compose a 'sed' expression out of # MSVCGEN_BUILD_ROOT in order to ensure that the referenced icon paths are # correct. However, we must take care to protect characters in # MSVCGEN_BUILD_ROOT which have special meaning to 'sed'. For instance, in # MSVCGEN_BUILD_ROOT, if $(TOP)/ is "./", then we want it to match a literal # period followed by a slash, not 'any character' followed by a slash, so it # must be transformed to "\./". (Presently we take the simple-minded approach # of protecting only "." since it arises frequently.) MSVCGEN_SED_PROTECT = "$(SED) 's:\\.:\\\\\\.:g'" ; MSVC_PLATFORM_SUFFIX = ; MSVC_VERSION ?= 7 ; if $(MSVC_VERSION) = 6 { SUFPRJ = dsp ; SUFWSP = dsw ; MSVC_SUFLIB = lii6iiib ; MSVC_SUFEXE = exe ; MSVC_FORCE_CRLF = yes ; MSVC_TEMPLATE_SUFFIX = 6 ; } else if $(MSVC_VERSION) = 7 || $(MSVC_VERSION) = 71 || $(MSVC_VERSION) = 8 || $(MSVC_VERSION) = sn71 || $(MSVC_VERSION) = xenon8 { SUFPRJ = vcproj ; SUFWSP = sln ; MSVC_SUFLIB = liiixxiib ; MSVC_SUFEXE = exe ; MSVC_FORCE_CRLF = no ; MSVC_TEMPLATE_SUFFIX = 7 ; if $(MSVC_VERSION) = 7 { MSVC_FORMATVERSION_PRJ = 7.00 ; MSVC_FORMATVERSION_WSP = 7.00 ; } else if $(MSVC_VERSION) = 71 { MSVC_FORMATVERSION_PRJ = 7.10 ; MSVC_FORMATVERSION_WSP = 8.00 ; } else if $(MSVC_VERSION) = 8 { MSVC_FORMATVERSION_PRJ = 8.00 ; MSVC_FORMATVERSION_WSP = 9.00 ; } else if $(MSVC_VERSION) = sn71 { MSVC_FORMATVERSION_PRJ = 7.10 ; MSVC_FORMATVERSION_WSP = 8.00 ; MSVC_TEMPLATE_SUFFIX = sn71 ; MSVC_SUFLIB = a ; MSVC_SUFEXE = elf ; } else if $(MSVC_VERSION) = xenon8 { MSVC_FORMATVERSION_PRJ = 8.00 ; MSVC_FORMATVERSION_WSP = 9.00 ; MSVC_TEMPLATE_SUFFIX = xenon8 ; MSVC_PLATFORM_SUFFIX = _xenon ; } } else { exit "No msvcgen support for MSVC version $(MSVC_VERSION) yet!" ; } MSVC.TSUFPRJ = tproj ; MSVC.TSUFWKP = twks ; MSVC.DEPEND ?= ; MSVC.DEPEND_DEBUG ?= ; MSVC.LIBRARY ?= ; MSVC.LIBRARY_DEBUG ?= ; MSVC.LFLAGS ?= ; MSVC.LFLAGS_DEBUG ?= ; MSVC.LIBRARY_DELAY ?= ; MSVC.CFLAGS ?= ; MSVC.CFLAGS_DEBUG ?= ; MSVC.DEFINES ?= ; MSVC.DEFINES_DEBUG ?= ; MSVC.DEPEND.appgui ?= ; MSVC.DEPEND_DEBUG.appgui ?= ; MSVC.LIBRARY.appgui ?= ; MSVC.LIBRARY_DEBUG.appgui ?= ; MSVC.LFLAGS.appgui ?= ; MSVC.LFLAGS_DEBUG.appgui ?= ; MSVC.CFLAGS.appgui ?= ; MSVC.CFLAGS_DEBUG.appgui ?= ; MSVC.DEFINES.appgui ?= ; MSVC.DEFINES_DEBUG.appgui ?= ; MSVC.DEPEND.appcon ?= ; MSVC.DEPEND_DEBUG.appcon ?= ; MSVC.LIBRARY.appcon ?= ; MSVC.LIBRARY_DEBUG.appcon ?= ; MSVC.LFLAGS.appcon ?= ; MSVC.LFLAGS_DEBUG.appcon ?= ; MSVC.CFLAGS.appcon ?= ; MSVC.CFLAGS_DEBUG.appcon ?= ; MSVC.DEFINES.appcon ?= ; MSVC.DEFINES_DEBUG.appcon ?= ; MSVC.DEPEND.plugin ?= ; MSVC.DEPEND_DEBUG.plugin ?= ; MSVC.LIBRARY.plugin ?= ; MSVC.LIBRARY_DEBUG.plugin ?= ; MSVC.LIBRARY_DELAY.plugin ?= ; MSVC.LFLAGS.plugin ?= ; MSVC.LFLAGS_DEBUG.plugin ?= ; MSVC.CFLAGS.plugin ?= ; MSVC.CFLAGS_DEBUG.plugin ?= ; MSVC.DEFINES.plugin ?= ; MSVC.DEFINES_DEBUG.plugin ?= ; MSVC.DEPEND.library ?= ; MSVC.DEPEND_DEBUG.library ?= ; MSVC.LIBRARY.library ?= ; MSVC.LIBRARY_DEBUG.library ?= ; MSVC.LFLAGS.library ?= ; MSVC.LFLAGS_DEBUG.library ?= ; MSVC.CFLAGS.library ?= ; MSVC.CFLAGS_DEBUG.library ?= ; MSVC.DEFINES.library ?= ; MSVC.DEFINES_DEBUG.library ?= ; MSVC.PREFIX.appgui ?= app ; MSVC.PREFIX.appcon ?= app ; MSVC.PREFIX.plugin ?= plg ; MSVC.PREFIX.library ?= lib ; MSVC.PREFIX.group ?= grp ; MSVC.PREFIX.workspace ?= wks ; SetProperty build : projgen : msvc ; SetProperty build : projgen_version : $(MSVC_VERSION) ; # MsvcAddPrefix name : type rule MsvcAddPrefix { local name = $(1) ; local type = $(2) ; local prefix = $(MSVC.PREFIX.$(type)) ; if $(prefix) { name = "$(prefix)$(name)" ; } return $(name) ; } #---------------------------------------------------------------------------- # Override some rules actions GenerateWin32ManifestRc { cat > $(<) << __EOF__ // This file is generated automatically. #if !defined(PROJECTGEN_VERSION) || (PROJECTGEN_VERSION != 8) 1 24 "$(MANIFEST_NAME)" #endif __EOF__ } ## MsvcGenConfig variable [ : value ] ## (See documentation above.) rule MsvcGenConfig1 { $(<) = $(>) ; } ## MsvcGenVariable variable [ : value ] ## (See documentation above.) rule MsvcGenVariable1 { MSVCGEN_VARIABLES += "$(<)|$(>)" ; } ## MsvcGenWorkspace name [ : accepts [ : rejects ]] ## (See documentation above.) rule MsvcGenWorkspace1 { local name = $(1) ; local accepts = $(2) ; local rejects = $(3) ; local builddir = [ msvcgen_build_dir $(MSVC_VERSION) ] ; local workdir = [ msvcgen_work_dir $(MSVC_VERSION) ] ; local wksname = $(MSVC.NAME_OVERRIDE.$(name)) ; if ! $(wksname) { wksname = [ MsvcAddPrefix $(name) : workspace ] ; } MSVC.WORKSPACES += $(name) ; local respdir = $(workdir) ; local respfile = $(wksname:G=msvcresp:S=.resp) ; Always $(respfile) ; $(name)_WKS_RESPFILE = $(respfile) ; $(name)_WKS_RESPDIR = $(respdir) ; # Boilerplate. ResponseFile $(respfile) : "key|value" "accept|$(accepts)" "reject|$(rejects)" "formatversion|$(MSVC_FORMATVERSION_WSP)" $(MSVCGEN_VARIABLES) : notfile : $(respdir) ; MsvcRmTemps msvcgen : $(respfile) ; local buildfile = $(wksname:G=msvcworkspace:S=.$(MSVC.TSUFWKP)) ; Always $(buildfile) ; MakeLocate $(buildfile) : $(builddir) ; Includes $(buildfile) : $(respfile) ; MSVC_BUILD_TYPE on $(buildfile) = workspace ; MsvcBuildFile $(buildfile) : $(respfile) ; Depends msvcgenrun : $(buildfile) ; MsvcRmTemps msvcgen : $(buildfile) ; } ## MsvcGenSubDir dircomponents [ : version ] ## (See documentation above.) rule MsvcGenSubDir1 { local path = $(1) ; local version = $(2) ; local relpath ; if ! $(path[2]) { relpath = $(DOT) ; } else { local i ; for i in $(path[2-]) { relpath += $(DOTDOT) ; } } SetProperty msvcgen : outdir$(version) : [ msvcgen_target_dir $(path) ] ; SetProperty msvcgen : relpath$(version) : $(relpath) ; MSVCGEN_OUTDIR_$(version) = [ Property msvcgen : outdir$(version) ] ; } ## MsvcGenTemplateDir dircomponents ## (See documentation above.) rule MsvcGenTemplateDir1 { SetProperty msvcgen : templatedir : [ msvcgen_template_dir $(<) ] ; MSVCGEN_TEMPLATEDIR = [ Property msvcgen : templatedir ] ; } ## MsvcGenName target : name ## (See documentation above.) rule MsvcGenName1 { MSVC.NAME_OVERRIDE.$(<) = $(>) ; } ## MsvcProject target : type : target-with-ext : sources : options ## Create a project file for 'target', which is the project's raw name. ## 'sources' is a list of files comprising the target. rule MsvcProject { local rawname = $(1) ; local type = $(2) ; local decorated = $(3) ; local sources = $(4) ; local options = $(5) ; local relpath = [ Property msvcgen : relpath$(MSVC_VERSION) ] ; local outdir = [ Property msvcgen : outdir$(MSVC_VERSION) ] ; local outdircommon = [ Property msvcgen : outdircommon ] ; if "$(outdircommon)" = "" { outdircommon = $(outdir) ; } local builddir = [ msvcgen_build_dir $(MSVC_VERSION) ] ; local workdir = [ msvcgen_work_dir $(MSVC_VERSION) ] ; local workdircommon = [ msvcgen_work_dir common ] ; local msvcname = $(MSVC.NAME_OVERRIDE.$(rawname)) ; if ! $(msvcname) { msvcname = [ MsvcAddPrefix $(rawname) : $(type) ] ; } $(rawname)_MSVCNAME = $(msvcname) ; local respdir = $(workdir) ; local respfile = $(msvcname:G=msvcresp:S=.resp) ; Always $(respfile) ; $(rawname)_PRJ_RESPFILE = $(respfile) ; $(rawname)_PRJ_RESPDIR = $(respdir) ; # Boilerplate. ResponseFile $(respfile) : "key|value" "formatversion|$(MSVC_FORMATVERSION_PRJ)" "projtype|$(type)" "project|$(msvcname)" "rawtarget|$(rawname)" "target|$(decorated)" "sourceroot|$(relpath:J=/)" "buildroot|$(relpath:J=/)" "striproot|$(MSVCGEN_STRIP_ROOT)" "define|$(MSVC.DEFINES)" "define|$(MSVC.DEFINES.$(type))" "definedebug|$(MSVC.DEFINES_DEBUG)" "definedebug|$(MSVC.DEFINES_DEBUG.$(type))" "cflags|$(MSVC.CFLAGS)" "cflags|$(MSVC.CFLAGS.$(type))" "cflagsdebug|$(MSVC.CFLAGS_DEBUG)" "cflagsdebug|$(MSVC.CFLAGS_DEBUG.$(type))" "lflags|$(MSVC.LFLAGS)" "lflags|$(MSVC.LFLAGS.$(type))" "lflagsdebug|$(MSVC.LFLAGS_DEBUG)" "lflagsdebug|$(MSVC.LFLAGS_DEBUG.$(type))" "library|$(MSVC.LIBRARY)" "library|$(MSVC.LIBRARY.$(type))" "librarydebug|$(MSVC.LIBRARY_DEBUG)" "librarydebug|$(MSVC.LIBRARY_DEBUG.$(type))" "librarydelay|$(MSVC.LIBRARY_DELAY)" "librarydelay|$(MSVC.LIBRARY_DELAY.$(type))" "msvcversion|$(MSVC_VERSION)" "static|$($(rawname)_STATIC)" "platformsuffix|$(MSVC_PLATFORM_SUFFIX)" $(MSVCGEN_VARIABLES) : notfile : $(respdir) ; MsvcRmTemps msvcgen : $(respfile) ; # Only include source and headers files for now. In the future, we also # want to include .cfg files and any other textual resources which which the # user might care to read/view in the MSVC IDE. local i ; for i in $(sources) { if [ IsElem $(i:S) : .h .hpp .hxx .H .c .cc .cpp .cxx .C .m .mm .M ] { local fileinproj ; if $($(rawname)_STATIC) = "yes" { fileinproj = $(i) ; } else { fileinproj = $(i:R=$(SEARCH_SOURCE)) ; } ResponseFile $(respfile) : "file|$(fileinproj)" : notfile : $(respdir) ; } } # Add resource file. if [ IsElem $(type) : plugin appgui appcon ] { local resource = $(msvcname:S=.rc) ; Depends msvcgen : $(resource) ; MakeLocate $(resource) : $(outdircommon) ; SEARCH on $(resource) = $(outdircommon) ; NAME on $(resource) = $(rawname) ; $(rawname)_RCNAME = $(resource) ; ResponseFile $(respfile) : "file|$(resource:R=$(outdircommon))" : notfile : $(respdir) ; local versionrc = $(resource:S=.vrctmp) ; MakeLocate $(versionrc) : $(workdircommon) ; MakeVersionRc $(versionrc) : $(rawname) ; Depends $(versionrc) : $(TOP)/Jamconfig ; Depends $(versionrc) : $(SUBDIR)/Jamfile ; Win32Resource $(rawname) : $(versionrc) ; MsvcRmTemps $(resource) : $(versionrc) ; if $(type) = "plugin" { local metarc = $(resource:S=.mrctmp) ; MakeLocate $(metarc) : $(workdircommon) ; SEARCH on $(metarc) = $(SEARCH_SOURCE) ; Depends $(metarc) : $($(rawname)_METAFILE) ; GenerateWin32MetadataRc $(metarc) : $($(rawname)_METAFILE) ; Win32Resource $(rawname) : $(metarc) ; MsvcRmTemps $(resource) : $(metarc) ; ResponseFile $(respfile) : "file|$($(rawname)_METAFILE:R=$(SEARCH_SOURCE))" : notfile : $(respdir) ; } if [ IsElem $(type) : appgui appcon ] { if ! [ IsElem nomanifest : $(options) ] { local manifest = $(msvcname:S=.manifest) ; MakeLocate $(manifest) : $(outdircommon) ; MakeManifestFile $(manifest) : $(rawname) ; Depends $(manifest) : $(TOP)/Jamconfig ; Depends $(manifest) : $(SUBDIR)/Jamfile ; Depends msvcgen : $(manifest) ; local manifestrc = $(resource:S=.mfrctmp) ; MakeLocate $(manifestrc) : $(workdircommon) ; MANIFEST_NAME on $(manifestrc) = $(manifest) ; GenerateWin32ManifestRc $(manifestrc) ; Depends $(manifestrc) : $(manifest) ; if $(MSVC_VERSION) = 8 { # VC8: Manifest appears in project along other files, a special build # tool cares about the embedding into a resource. (The resource goop # still has to be generated since it is shared with other VCs.) ResponseFile $(respfile) : "file|$(manifest:R=$(outdircommon))" : notfile : $(respdir) ; } Win32Resource $(rawname) : $(manifestrc) ; MsvcRmTemps $(resource) : $(manifestrc) ; } local icon = [ ApplicationIcon win32 : $(rawname) ] ; if ! $(icon) { local apptype = gui ; if $(type) = "appcon" { apptype = console ; } icon = [ ApplicationIconDefault win32 : $(apptype) ] ; } if $(icon) { local iconrc = $(resource:S=.iconrctmp) ; # RELPATH includes trailing slash (hence the "" in ConcatDirs). RELPATH on $(iconrc) = [ ConcatDirs [ Property msvcgen : relpath$(MSVC_VERSION) ] "" ] ; MakeLocate $(iconrc) : $(workdircommon) ; Depends $(iconrc) : $(icon) ; Depends $(iconrc) : $(SUBDIR)/Jamfile ; GenerateIconRc $(iconrc) : $(icon) ; Win32Resource $(rawname) : $(iconrc) ; MsvcRmTemps $(resource) : $(iconrc) ; } } } local inckeys = "include" includedebug ; local incdirs = $(MSVC.INCDIRS_LITERAL) $(MSVC.INCDIRS_LITERAL.$(rawname)) ; ResponseFile $(respfile) : "$(inckeys)|$(incdirs)" : notfile : $(respdir) ; local incdir ; for incdir in $(MSVC.INCDIRS) $(MSVC.INCDIRS.$(rawname)) { if $(incdir) = "." { incdir = [ ConcatDirs $(relpath) ] ; } else { incdir = [ ConcatDirs $(relpath) $(incdir) ] ; } ResponseFile $(respfile) : "$(inckeys)|$(incdir)" : notfile : $(respdir) ; } if ! [ Property msvcgen : templatedir ] { exit "Error: You must invoke MsvcGenTemplateDir for project generation." ; } local buildfile = $(msvcname:G=msvcproject:S=.$(MSVC.TSUFPRJ)) ; Always $(buildfile) ; MakeLocate $(buildfile) : $(builddir) ; Includes $(buildfile) : $(respfile) ; MSVC_BUILD_TYPE on $(buildfile) = project ; MsvcBuildFile $(buildfile) : $(respfile) ; Depends msvcgenrun : $(buildfile) ; MsvcRmTemps msvcgen : $(buildfile) ; if ! $(MSVC.WORKSPACES) { exit "You must specify at least one workspace via MsvcGenWorkspace" ; } local w ; for w in $(MSVC.WORKSPACES) { ResponseFile $($(w)_WKS_RESPFILE) : "project|$(msvcname)" : notfile : $($(w)_WKS_RESPDIR) ; } Clean msvcclean : $(target) ; } #---------------------------------------------------------------------------- # Ensure that the pseudo-groups exist with which the overridden Application, # Plugin, and Library rules will register their targets. We have to do this # here rather than at the top-level (outside of any rule invocation) because we # need to give the client time to invoke MsvcGenWorkspace first to set up the # workspaces into which these groups will be inserted. If we tried registering # theses pseudo-groups at the top-level, registration would occur before the # client has had a chance to invoke MsvcGenWorkspace, thus these pseudo-groups # would not inhabit any workspaces. rule RegisterWellKnownCompileGroup1 { local group = $(1) ; if $(MSVCGEN.WELL_KNOWN_GROUP_REGISTERED.$(group)) != yes { MSVCGEN.WELL_KNOWN_GROUP_REGISTERED.$(group) = yes ; RegisterCompileGroups $(group) ; } } rule RegisterWellKnownCompileGroup { RegisterWellKnownCompileGroup1 all ; RegisterWellKnownCompileGroup1 $(1) ; } rule LinkStaticPlugins { local package target plugins optplugins ; # Fetch the parameters target = $(1) ; plugins = $(2) ; optplugins = $(3) ; package = $(4) ; if $(package) { # External static plugins. # First include static plugin info if ! $(HAVE_STATICDEPS.$(package)) { include $($(package).STATICDEPS) ; HAVE_STATICDEPS.$(package) = yes ; } local lflags.debug lflags.release p mode ; # Collect optional plugins for p in $(optplugins) { if [ IsElem $(p) : $(STATICPLUGINS.AVAILABLE) ] { plugins += $(p) ; } } # Grab flags for p in $(plugins) { NotFile $(p) ; for mode in debug release { MsvcCFlags $(target) : $(STATICPLUGIN.$(p).CFLAGS.$(mode)) : $(mode) ; lflags.$(mode) += $(STATICPLUGIN.$(p).LFLAGS.$(mode)) ; } } for mode in debug release { MsvcLFlags $(target) : [ Reverse [ RemoveDups [ Reverse $(lflags.$(mode)) ] ] ] : $(mode) ; } } else { # link with static plugins LinkWith $(target) : $(STATICPLUGINS.LIBRARY) ; # Local static plugins local libs p ; # Collect optional plugins for p in $(optplugins) { if $($(p)_TYPE) { plugins += $(p) ; } } # Grab flags for p in $(plugins) { libs += $($(p).NEEDLIBS) ; ExternalLibs $(target) : $($(p).EXTERNALLIBS) ; for mode in debug release { MsvcExternalLibrary $(target) : $($(p)_$(mode)_EXTERNALLIBS) : $(mode) ; MsvcExternalLibrary $(target) : $($(p)_$(mode)_EXTERNALLIBS) : $(mode) ; } } LinkWith $(target) : $(libs) ; } # Generate static plugin instantiation local outdir = [ Property msvcgen : outdircommon ] ; if "$(outdir)" = "" { outdir = [ Property msvcgen : outdir$(MSVC_VERSION) ] ; } local staticuse_out ; if $(package) { # @@@ Prefix hardcoded staticuse_out = $(MSVC.PREFIX.appgui)$(<)_staticuse_$(package).cpp ; } else { staticuse_out = $(MSVC.PREFIX.appgui)$(<)_staticuse.cpp ; # @@@ Prefix hardcoded } MakeLocate $(staticuse_out) : $(outdir) ; SEARCH on $(staticuse_out) = $(outdir) ; GenerateStaticPluginInstantiation $(staticuse_out) : $(plugins) ; Depends msvcgen : $(staticuse_out) ; # Add usefile to project ResponseFile $($(target)_PRJ_RESPFILE) : "file|$(staticuse_out:R=$(outdir))" : notfile : $($(target)_PRJ_RESPDIR) ; Depends $(target) : $(staticuse_out) ; } rule Application { RegisterWellKnownCompileGroup apps ; local projtype ; if [ IsElem console : $(3) ] { projtype = appcon ; } else { projtype = appgui ; } MsvcProject $(<) : $(projtype) : $(<:S=.$(MSVC_SUFEXE)) : $(>) : $(3) ; CompileGroups $(<) : all apps ; } rule Plugin { RegisterWellKnownCompileGroup plugins ; $(<)_TYPE = plugin ; local metafile ; metafile = [ FAppendSuffix $(<) : $(SUFMETA) ] ; SEARCH on $(metafile) = $(SEARCH_SOURCE) ; $(<)_METAFILE = $(metafile) ; MsvcProject $(<) : plugin : $(<:S=$(MSVCGEN.PLUGIN_EXT.$(<):E=.dll)) : $(>) ; CompileGroups $(<) : all plugins ; STATICPLUGINS.SOURCES.$(<) += $(>:R=$(SEARCH_SOURCE)) ; STATICPLUGINS.SUBTARGETS += $(<) ; # Generate static variant of plugin # Static registry local outdir = [ Property msvcgen : outdircommon ] ; local staticreg_out = $(MSVC.PREFIX.library)$(<)_staticreg.cpp ; MakeLocate $(staticreg_out) : $(outdir) ; SEARCH on $(staticreg_out) = $(outdir) ; GenerateStaticPluginRegistration $(staticreg_out) : $(metafile) ; Depends msvcgen : $(staticreg_out) ; STATICPLUGINS.SOURCES.$(<) += $(outdir)/$(staticreg_out) ; } rule Library { RegisterWellKnownCompileGroup libs ; $(<)_TYPE = library ; MsvcProject $(<) : library : $(<:S=.$(MSVC_SUFLIB)) : $(>) ; CompileGroups $(<) : all libs ; } rule StaticPluginLibrary { local name = $(<) ; local rejects = $(>) ; local t ; local targets = $(STATICPLUGINS.SUBTARGETS) ; if $(rejects) { targets = [ Filter $(targets) : $(rejects) ] ; } local sources ; for t in $(targets) { sources += $(STATICPLUGINS.SOURCES.$(t)) ; } $(name)_STATIC = "yes" ; # Set up library Library $(name) : $(sources) ; MsvcDefine $(name) : CS_STATIC_LINKED ; _MsvcDefine $(name) : $(STATICPLUGINS.MSVC_DEFINES) ; # Write out needed CFLAGS, LFLAGS local outdir = [ Property msvcgen : outdircommon ] ; if $(outdir) = "" { outdir = [ Property msvcgen : outdir$(MSVC_VERSION) ] ; } STATICPLUGINS.DEPENDENCIES = $(name)_msvc.jam ; MakeLocate $(STATICPLUGINS.DEPENDENCIES) : $(outdir) ; SEARCH on $(STATICPLUGINS.DEPENDENCIES) = $(outdir) ; for t in $(targets) { NotFile $(t) ; WriteDependencies $(STATICPLUGINS.DEPENDENCIES) : $(t) : $(name) ; } Always $(STATICPLUGINS.DEPENDENCIES) ; Depends msvcgen : $(STATICPLUGINS.DEPENDENCIES) ; STATICPLUGINS.LIBRARY = $(name) ; } # Write out CFLAGS, LFLAGS needed by a plugin rule WriteDependencies { local cflags.debug cflags.release ; local lflags.debug lflags.release ; local depfile = $(<) ; local plugin = $(>) ; local libname = $(3) ; local depfile_gristed = $(depfile:G=$(plugin)) ; MakeLocate $(depfile_gristed) : [ on $(depfile) GetVar LOCATE ] ; # "Artificially" insert static library itself lflags.debug += $(MSVC.PREFIX.library)$(libname)_d.$(MSVC_SUFLIB) ; lflags.release += $(MSVC.PREFIX.library)$(libname).$(MSVC_SUFLIB) ; # Collect other libs local libs = [ ResolveLibs $($(plugin).NEEDLIBS) ] ; lflags.debug += $(MSVC.PREFIX.library)$(libs)_d.$(MSVC_SUFLIB) ; lflags.release += $(MSVC.PREFIX.library)$(libs).$(MSVC_SUFLIB) ; # Defines local l ; for l in $($(plugin).EXTERNALLIBS) { if $($(l).DEFINES.DEBUG) { cflags.debug += "\"/D $($(l).DEFINES.DEBUG)\"" ; cflags.release += "\"/D $($(l).DEFINES)\"" ; } else { cflags.debug += "\"/D $($(l).DEFINES)\"" ; cflags.release += "\"/D $($(l).DEFINES)\"" ; } } # Link flags local mode ; for mode in debug release { lflags.$(mode) += $($(plugin).LFLAGS.$(mode)) ; lflags.$(mode) += $($(plugin)_$(mode)_EXTERNALLIBS) ; } CFLAGS.DEBUG on $(depfile_gristed) = "$(cflags.debug)" ; CFLAGS.RELEASE on $(depfile_gristed) = "$(cflags.release)" ; lflags.debug = [ RemoveDups $(lflags.debug) ] ; LFLAGS.DEBUG on $(depfile_gristed) = "$(lflags.debug)" ; lflags.release = [ RemoveDups $(lflags.release) ] ; LFLAGS.RELEASE on $(depfile_gristed) = "$(lflags.release)" ; LIBNAME on $(depfile_gristed) = $(libname) ; if $($(depfile).FIRSTTIME) != "yes" { WriteDepFlags1 $(depfile_gristed) : $(plugin) ; $(depfile).FIRSTTIME = "yes" ; } else { WriteDepFlags2 $(depfile_gristed) : $(plugin) ; } Depends $(depfile) : $(depfile_gristed) ; Always $(depfile_gristed) ; } actions WriteDepFlags1 { cat << EOT > $(<) # This file is automatically generated to be used together with $(LIBNAME) # and must be integrated by setting the correct values for the # HAVE_STATICDEPS. and .STATICDEPS via MsvcGenConfig. # Furthermore, this file might require manual updates from the master copy # (usually found in the package's source repository) every now and then. STATICPLUGINS.AVAILABLE += $(>) ; STATICPLUGIN.$(>).CFLAGS.debug = $(CFLAGS.DEBUG) ; STATICPLUGIN.$(>).CFLAGS.release = $(CFLAGS.RELEASE) ; STATICPLUGIN.$(>).LFLAGS.debug = $(LFLAGS.DEBUG) ; STATICPLUGIN.$(>).LFLAGS.release = $(LFLAGS.RELEASE) ; EOT } actions WriteDepFlags2 { cat << EOT >> $(<) STATICPLUGINS.AVAILABLE += $(>) ; STATICPLUGIN.$(>).CFLAGS.debug = $(CFLAGS.DEBUG) ; STATICPLUGIN.$(>).CFLAGS.release = $(CFLAGS.RELEASE) ; STATICPLUGIN.$(>).LFLAGS.debug = $(LFLAGS.DEBUG) ; STATICPLUGIN.$(>).LFLAGS.release = $(LFLAGS.RELEASE) ; EOT } rule RegisterCompileGroups { local i ; for i in $(<)_$(MSVC.WORKSPACES) { MsvcProject $(i) : group ; } } rule CompileGroups { local w ; for w in $(MSVC.WORKSPACES) { local i ; for i in $(>)_$(w) { local m = $($(<)_MSVCNAME) ; if ! $(m) { m = $($(<)_$(w)_MSVCNAME) ; } # Might be a "group". if $(m) { ResponseFile $($(w)_WKS_RESPFILE) : "$($(i)_MSVCNAME)|$(m)" : notfile : $($(w)_WKS_RESPDIR) ; } } } } rule LinkWith { local libs = [ ResolveLibs $(>) ] ; ExternalLibs $(<) : $($(>).EXTERNALLIBS) ; local w ; for w in $(MSVC.WORKSPACES) { local l ; for l in $(libs)_MSVCNAME { if $($(l)) { ResponseFile $($(w)_WKS_RESPFILE) : "$($(<)_MSVCNAME)|$($(l))" : notfile : $($(w)_WKS_RESPDIR) ; } } } $(<).NEEDLIBS = $(libs) ; } rule MsvcClassifyMode { local c ; switch $(<) { case release : c = "" ; case debug : c = debug ; case * : c = "" debug ; } return $(c) ; } # _MsvcRespEmit target : items : tag [ : mode [ : options ]] # Emit `items' to the response file for `target' using the response file tag # `tag'. `mode' is either "release", "debug", or empty, in which case it # applies to release and debug modes. If options contains "ignoremode", then # `mode' is not consulted. rule _MsvcRespEmit { local target = $(1) ; local items = $(2) ; local tag = $(3) ; local mode = $(4) ; local options = $(5) ; local modes = "" ; CheckOptions ignoremode : $(options) : $(target) ; if ! [ IsElem ignoremode ] { modes = [ MsvcClassifyMode $(mode) ] ; } ResponseFile $($(target)_PRJ_RESPFILE) : "$(tag)$(modes)|$(items)" : notfile : $($(target)_PRJ_RESPDIR) ; } # MsvcExternalLibrary target [ : libs [ : mode ]] # (See documentation above.) rule MsvcExternalLibrary1 { _MsvcRespEmit $(1) : $(2) : library : $(3) ; local mode = $(3) ; mode ?= debug release ; $(1)_$(mode)_EXTERNALLIBS += $(2) ; } # MsvcDefine target [ : key [ : value [ : mode ]]] # (See documentation above.) rule MsvcDefine1 { local target = $(1) ; local key = $(2) ; local value = $(3) ; local mode = $(4) ; if $(key) { local def ; if $(value) { def = "$(key)=$(value)" ; } else { def = $(key) ; } _MsvcRespEmit $(target) : $(def) : define : $(mode) ; STATICPLUGINS.MSVC_DEFINES += $(def) ; } } # MsvcIncDirs target : directory [ : mode ] # (See documentation above.) rule MsvcIncDirs1 { _MsvcIncDirs $(1) : $(2) : $(3) ; } # _MsvcDefine target : tuples [ : mode ] # Similar to MsvcDefine, but works with a list of `key=value' tuples. Also # understands `key' with no value. rule _MsvcDefine { _MsvcRespEmit $(1) : $(2) : define : $(3) ; } # MsvcCFLags target [ : cflags [ : mode ]] # (See documentation above.) rule MsvcCFlags1 { _MsvcRespEmit $(1) : $(2) : cflags : $(3) ; } # MsvcLFlags target [ : lflags [ : mode ]] # (See documentation above.) rule MsvcLFlags1 { local modes = [ MsvcClassifyMode $(3) ] ; $(target).LFLAGS.$(modes) += $(2) ; _MsvcRespEmit $(1) : $(2) : lflags : $(3) ; } # _MsvcIncDirs target : incdirs [ : mode ] # Helper for ExternalLibs which processes the contents of TAG.INCDIRS for # an external library. rule _MsvcIncDirs { _MsvcRespEmit $(1) : $(2) : include : $(3) ; } # _MsvcLibDirs target : libdirs [ : mode ] # Helper for ExternalLibs which processes the contents of TAG.LIBDIRS for # an external library. rule _MsvcLibDirs { _MsvcRespEmit $(1) : $(2) : libdir : $(3) ; } # _ExternalLibsHelperMsvc target : libtag : subrule : attribute rule _ExternalLibsHelperMsvc { local target = $(1) ; local lib = $(2) ; local rulename = $(3) ; local attrib = $(4) ; if $($(lib).$(attrib).DEBUG.$(MSVC_VERSION)) { $(rulename) $(target) : $($(lib).$(attrib).DEBUG.$(MSVC_VERSION)) : debug ; } else if $($(lib).$(attrib).DEBUG) { $(rulename) $(target) : $($(lib).$(attrib).DEBUG) : debug ; } else { $(rulename) $(target) : $($(lib).$(attrib)) : debug ; } if $($(lib).$(attrib).$(MSVC_VERSION)) { $(rulename) $(target) : $($(lib).$(attrib).$(MSVC_VERSION)) : release ; } else { $(rulename) $(target) : $($(lib).$(attrib)) : release ; } } rule ExternalLibs { local i ; for i in $(>) { _ExternalLibsHelperMsvc $(<) : $(i) : MsvcCFlags : CFLAGS ; _ExternalLibsHelperMsvc $(<) : $(i) : MsvcLFlags : LFLAGS ; _ExternalLibsHelperMsvc $(<) : $(i) : MsvcExternalLibrary : LIBS ; _ExternalLibsHelperMsvc $(<) : $(i) : _MsvcDefine : DEFINES ; _ExternalLibsHelperMsvc $(<) : $(i) : _MsvcIncDirs : INCDIRS ; _ExternalLibsHelperMsvc $(<) : $(i) : _MsvcLibDirs : LIBDIRS ; $(<).EXTERNALLIBS += $(i) ; } } rule IncludeDir { local dir = $(1) ; local target = $(2) ; local options = $(3) ; if ! [ IsElem transient : $(options) ] { local tag = "INCDIRS" ; if [ IsElem literal : $(options) ] { tag = "INCDIRS_LITERAL" ; } if $(dir) { dir = [ ConcatDirs $(dir) ] ; } else { dir = "." ; } if $(target) { MSVC.$(tag).$(target) += $(dir) ; } else { MSVC.$(tag) += $(dir) ; } } } # Normal invocations of these two rules are made using Unix-style flags; # possibly determined by an Autoconf configuration script. Such flags are # unsuitable for MSVC, so we ignore them. rule CFlags { } rule LFlags { } rule Win32Resource { Depends $(<) : $($(<)_RCNAME) ; Depends $($(<)_RCNAME) : $(>) ; MergeResources $($(<)_RCNAME) : $(>) ; } #---------------------------------------------------------------------------- actions MsvcBuildFile { cat > $(<) <) > $(<) } actions GenerateIconRc { sedexpr=`echo 's^$(MSVCGEN_STRIP_ROOT)^^;' | $(MSVCGEN_SED_PROTECT)` icon=`echo "$(>)" | sed "$sedexpr"` echo "1 ICON \"$(RELPATH)$icon\"" > $(<) } #---------------------------------------------------------------------------- rule MsvcTTreeRc { local target = $(<:G=ttreerc$(MSVC_VERSION)) ; local builddir = [ msvcgen_build_dir $(MSVC_VERSION) ] ; local workdir = [ msvcgen_work_dir $(MSVC_VERSION) ] ; WORKDIR on $(target) = $(workdir) ; BUILDDIR on $(target) = $(builddir) ; MakeLocate $(target) : $(workdir) ; MsvcTTreeRc1 $(target) ; Always $(target) ; Depends msvcgenrun : $(target) ; MsvcRmTemps msvcgen : $(target) ; return $(target) ; } actions MsvcTTreeRc1 { cat > $(<) <) $(MSVCGEN_TTREEOPTIONS) --load_perl --all $(PERL) -pi.bak \ -e 'if ($ARGV ne $prev) { $prev = $ARGV; binmode(ARGVOUT) }' \ -e 's:(?) $(MSVCGEN_TTREEOPTIONS) --load_perl --all } } MsvcTTree msvcgenrun : [ MsvcTTreeRc ttree.rc ] ; NotFile msvcgen ; Always msvcgen ; Depends msvcgen : msvcgenrun ; }