PowerMaker language (TDK)
Typically, you do not need to know about the PowerMaker utility or PowerMaker language, because TDK uses the PowerMaker utility without you having to interact with it.
This topic describes the language that PowerMaker understands when reading a configuration file.
Comments
Comments start with the hash character (#) and are effective up to the end of the line.
Tokens
Keywords are lowercase words only.
Identifiers can include letters, digits and underscores in any order and combination.
Variable names start with either a dollar "$" or a "@" character, then proceed as standard identifiers.
Constants can be single quoted strings and double quoted strings. Single quoted constants can contain double quoted characters that do not need to be escaped because the context is single quoted. The reverse is true for double quoted strings.
An extra constant none exists. It is like the empty string, but it is more expressive in certain situations, where the configuration file author takes care to show that no value is being assigned to a variable.
Path names are a special form of constants used for identifying files and directories.
Escaping is possible inside both single and double quoted variables, and the backslash character is used for this:
"\"" is a constant with a single double quoted character ('"' is the same)
"\n" is the line feed character
"\r" is the carriage return character
"\\" is a single backslash character
Escaping takes place for every literal constant, except for path names. In path names, the use of the backslash character is so common that it is not convenient to have to double it. Path names are used only in the context of list constructors (see the List Constructors section that follows). Any other use of quoting is a regular constant (with escaping).
Everything (identifiers, keywords and names) is case sensitive.
Configurations
The possible configurations have to be declared at the beginning of the configuration file. Each configuration is represented by an identifier.
This is an example of a configuration declaration (it declares 3 configurations and it must be the first statement in the configuration file):
config Debug, Release, OptimizedRelease;
While PowerMaker executes, there is a current configuration (the one specified on the command line). The value (name) of the current configuration is stored in the predefined variable $Current.
Variables, Expressions and Assignments
A variable has to be declared before being used. Variables can contain either a single value or a list of values. All values are string values.
The first character of a variable is a special character ($ or @). It decides whether it is a scalar (one value) or a (many values). The first character is $ for scalar variables and for list variables (just as in Perl scripting language).
Examples of variable declarations:
var $A; #declares a single value variable $A
var $A = 'TheValue'; #declares as above and assigns the value TheValue
var $A = "TheValue"; #declares as above and assigns the value TheValue
var $A = '"TheValue"'; #declares as above and assigns the value "TheValue" #i.e. *double* quotes ARE stored in the value
var $A = "'TheValue'"; #declares as above and assigns the value 'TheValue' #i.e. *single* quotes ARE stored in the value
var @A; #declares a list value variable @A
var @A = <some list expression>; #declares and assigns
Expressions can be basic (ordinary) expressions or configuration expressions. Configuration expressions have the ability to change their value depending on the current configuration. The default operator is concatenation, that is, the result is the set of values specified, chained together in the same order they appear. List to scalar conversion follows the same rule. The context of where it is used determines whether the result is scalar or a list. In assignments, the context is given by the type of the variable to the left of the "=" operator. It is a list context when it is a list, a scalar context when it is not a list. Internally, the interpreter always treats expressions as list expressions. The list-to-scalar conversion takes place after the result has been evaluated, just before the assignment (or the use of the expression) is made in a scalar context.
* 
The following occurs:
Conversion from list to scalar, a blank character is inserted between each value pair that is concatenated.
Scalar concatenation to scalar, no blank character is inserted, except when the evaluates expression is a command (see below). Command expression evaluation automatically inserts a blank when concatenating scalars (or list values).
Basic expressions in assignment contexts:
$A = "Constant" $B; #result is scalar (because $A is a scalar), it is Constant (without quotes) concatenated with the contents of $B.
$A = "Constant" @B; #result is scalar, it is Constant (without quotes) concatenated with the contents of all the elements of the @B list, concatenated together in the order they appear in the list.
@C = @A @B; #result is a list containing all the elements of @A followed by all the elements of @B.
@C = $A @B; #result is a list (because the value on the left of "=" is a list). It contains the value of $A, followed by all the values of @B.
Configuration expressions select which expression should be evaluated depending on the current configuration value. The structure of a configuration expression is described in the following example:
$CppSwitch = [Debug] "/Zi /Od", [Release] "/O1", [OptimizedRelease] "/O2 " $OtherOptimizations;
where result is /Zi /Od if the current configuration is Debug, /O1 if it is Release and /O2 <contents of $OtherOptimizations if it is OptimizedRelease. More complex expressions are possible (for example, among lists) with the same rule.
A configuration expression is a list of expressions separated by a comma, each preceded by a configuration in square brackets.
It is also possible to group configurations together, as follows:
$CppSwitch = [Debug] "/Zi /Od", [Release, OptimizedRelease] "/O2";
In this case, result is /Zi /Od when current configuration is Debug, /O2 when it is Release or OptimizedRelease.
Name rules
Name rules are a way of specifying text transformations. They are used specifically for changing paths/names/extensions of filenames.
A name rule is defined as follows:
namerule Cpp2H = $Path "\\" $Name ".h";
A name rule is invoked in the context of one or more expressions, as follows:
$A = Cpp2H ($B);
In this example, $B is first treated as a filename and separated in its basic components ($Name, $Path). Components act like predefined variables in the context of the name rule expression. The name rule assembles the component and the constants specified in its expression. The name rule expression can contain other predefined variables (for example, $Config), constants, user defined variables as any other regular (or configuration) expression. If a configuration expression, it will select the way the input argument is transformed on the value of the current configuration.
Name rules can be applied to list values too. For example:
@A = Cpp2H (@B); #transforms all single values of @B following the rule and assigns @A with the same values.
@A = Cpp2H (@B $C); #transforms all single values of @B, the transforms the scalar value $C, then assigns @A with the transformed values (transformed-of-$C will be the last in @A).
$A = Cpp2H (@B); #result is scalar, so it is the concatenation of all the transformed values of @B
List constructors
List constructors are used to fill list variables 0077ith filenames. List constructor have the following syntax:
1. Explicitly supplied file list:
var @A = from ".\MyDir\MySubDir" files
"File1.cpp"
"File2.cpp"
end files;
Sets @A to a list of two values, ".\MyDir\MySubDir\File1.cpp" and ".\MyDir\MySubDir\File2.cpp".
* 
The file system is not checked for the existence of such files. Since the file list is explicitly given, the language assumes that the files exist (or at least that you really want to initialize a variable with those names).
The directory name is a path name, so backslash escaping does not take place (you don't have to double backslashes).
Also note that the period is the target directory (the one specified on PowerMaker command line).
2. Path and pattern:
var @A = from ".\MySubDir" like "*.cpp";
Sets @A to the list of files that have a cpp extension in the ".\MySubDir" folder.
* 
In this case, PowerMaker searches in a specified folder for files that have a specified extension.
Resulting values will contain the directory specified after from (they are not the bare file names, they are the file names with ".\MySubDir\" applied in front of them).
3. File:
var @A = from ".\MySubDir\MyFile";
Sets @A to the list of the names that reside in ".\MySubDir\MyFile". Names should appear in the specified file one per line. Names do not have to be real filenames, but have to be double quoted, one per line. No escaping takes place. Before taking each value, quoting characters are removed. The file system is not involved.
* 
A three line MyFile contents:
"C:\DirA\DirB\ARealFile.cpp"
".\DirC\ArealFile.h"
"ThisIsNotAFileName"
Make rules
A make rule is a construct that produces one or more rules in the generated makefile. A make rule has two components, the subexpression section and the command section.
The subexpression section contains two or more assignments, possibly with variable declarations. At least the $ Source and the $Target scalar predefined variables have to be assigned to some kind of expression. $Source and $Target are the source and the target of the resulting makefile rules.
The command section contains one or more commands to be executed when the makefile engine discovers that the rule targets are out of date, or do not exist.
This is a simple rule:
rule Cpp_To_Obj
$Source = $MyFile Cpp2H ($MyFile);
$Target = Cpp2Obj ($MyFile);
Command
'cl' $CppOpt $MyFile;
end command;
end rule;
The preceding rule generates the following in the makefile (assuming $MyFile is "a.cpp", Cpp2H and Cpp2Obj change the extension in .h and .obj respectively, $CppOpt is "/O2"):
a.obj: a.cpp a.h
<one tab character>cl /O2 a.cpp
* 
Some blank characters are inserted automatically. This happens:
When the list containing $MyFile and Cpp2H ($MyFile) is converted to the scalar $Source (as part of the standard list-to-scalar translation process), so the result is "a.cpp a.h" instead of "a.cppa.h".
When the command expression is evaluated (just because it is a command expression), so the result is "cl /O2 a.cpp" instead of "cl/O2a.cpp".
Also note that the tab character starting a command is automatically generated. You should not specify it in the command expression.
A more complex rule:
rule Cpp_To_Obj foreach $File in @ListOfCpp do
$Source = $File Cpp2H ($File);
$Target = Cpp2Obj ($File);
Command
'cl' $CppOpt $File;
end command;
end rule;
The rule above uses the foreach construct. That rule is generated to the output makefile once per element in the @ListOfCpp list variable. Rules with such a foreach construct should be used when makefile rules and input files have a one-to-one relationship (and they are more than one).
Another example (typically used for linking):
rule Link
$Source = Cpp2Obj (@ListOfCpp);
$Target = $TargetExeFile;
var $OutTarget = "/OUT:" $TargetExeFile;
command
'link' $SomeLinkOptions $OutTarget $Source;
end command;
end rule;
* 
The preceding rule declares a local variable $OutTarget. This is done for getting a "/OUT:MyFile.exe" value without blank between "/OUT:" and the filename, which would cause a problem with the linker. A blank would have been inserted by the evaluation of the command expression if it had been:
'link' $SomeLinkOptions "/OUT:" $TargetExeFile $Source;
The preceding rule uses the list-to-scalar conversion mechanism for building the object-to-link list. Typically used when one single makefile rule is related to many input files.
There is a third situation, illustrated by the rule that follows:
rule CleanObj
$Source = none;
$Target = "CLEANALLOBJ";
command
'echo Cleaning Objs';
end command;
command foreach $File in Cpp2Obj (@ListOfCpp) do
'cmd /S /C if exist' $File 'del' $File;
end command;
end rule;
This rule should exist only once in the generated makefile, but it should contain a variable amount of commands depending on the cardinality of the @ListOfCpp variable. To get this, the foreach construct is now attached at the command (not at the rule as above). This should be used when the relationship rule-command is one-to-many.
* 
This rule has two command constructs: the first is generated just once, the latter once for each list element. A rule can generally have as many commands as needed.
The output of the rule above is as follows:
CLEANALLOBJ:
<one tab character>echo Cleaning Objs
<one tab character> cmd /S /C if exist a.obj del a.obj
<one tab character> cmd /S /C if exist b.obj del b.obj
… and so on …
Predefined values
There are some predefined variables and substitution tokens that are useful when defining makefiles. Substitution tokens are special predefined values that start and end with a percent character "%". Before outputting a string to the makefile, PowerMaker replaces such tokens with specified values that depend on the execution and environment.
Predefined values are listed here:
$Source, $Target: are predefined (in the context of a rule) in the sense that they must not be declared. They have to be initialized, however (at least to none). They are not initialized by the system to any value.
%CURR_DIR%: read only substitution token, evaluates to the full path of the target directory (no trailing "\"). So it's different from "." that is the current directory relative path.
%RTS_ROOT%: read only substitution token, evaluates to the full path of Modeler root, that is, "C:\Program Files\Windchill Modeler\Modeler" when Modeler is installed to the default locations.
%SHADOW_COMDIR%: read only substitution token, evaluates to the ACS communication directory (the same value of the SHADOW_COMDIR environment variable).