084e691be2
For Unified, set XAMCORE_2_0, UNIFIED and __UNIFIED__. For Xamarin.iOS/tvOS/watchOS set both the normal and underscored versions (IOS and __IOS__, TVOS and __TVOS__, and WATCHOS and __WATCHOS__). The underscored versions are the public symbols we're setting in the corresponding projects, so we should use those everywhere to simplify our code, but due to historical reasons we're still using the other variants in existing code. Making sure all the possible variants are set for all projects, makes it possible to only use the underscored versions in new code. Also define `GENERATOR` for the generator, so that we can easily share files between the generator and platform assemblies. |
||
---|---|---|
.. | ||
CSharp | ||
profiles | ||
tests | ||
.gitignore | ||
BuiltinProfiles.cs | ||
Driver.cs | ||
Makefile | ||
Makefile.frag | ||
Parser.cs | ||
Preprocessor.cs | ||
Profile.cs | ||
README.md | ||
Replacement.cs | ||
Settings.cs | ||
Timer.cs | ||
XamarinPreprocessorVisitor.cs | ||
pmcs | ||
pmcs.csproj |
README.md
pmcs: preprocessing frontend to mcs
pmcs performs search and replace operations on source code before invoking the actual mcs C# compiler. Original input files are not modified by default; rather, temporary files are passed to the compiler containing the preprocessed source code.
Search and replace operations are not performed for the entire contents
of a file. Instead, the preprocessor is aware of C# comments and string
literals. It will only perform replacements on "tokens" in C# code, where a
"token" is a group of characters being letters, digits, or one of _
, .
,
or :
.
Command Line Options
Option | Description |
---|---|
-h , -help |
Show help |
-v , -verbose |
Be verbose with output |
-compiler:VALUE |
Set the mcs compiler executable to invoke to VALUE |
-P , -profile:VALUE |
Load a pmcs XML profile from VALUE ; see XML Profiles |
-ignore:VALUE |
Do not preprocess VALUE |
-global-replace:VALUE |
Define a global replacement where VALUE = PATTERN=REPLACEMENT ; see Replacement Definitions on the Command Line |
-enum-replace:VALUE |
Define an enum backing type replacement where VALUE = PATTERN=REPLACEMENT ; see Replacement Definitions on the Command Line |
-target:VALUE |
specifies the format of the output assembly |
-omit-line-directive |
Do not generate a C# #line directive at the start of preprocessed files |
-skip-mdb-rebase |
do not rebase path names in .mdb symbol files (if -debug was specified) |
-skip-compile |
Do not perform compilation (preprocess only) |
-keep |
Do not delete preprocessed intermediate files (implied with -in-place ) |
-in-place |
Preprocess in place instead of outputting intermediate files. WARNING: this can be dangerous -- only use this option if your sources are under version control and do not have local changes or are otherwise backed up. |
-stdout |
Write preprocessed output to standard output (implies -skip-compile and no files on disk are modified) |
MDB Rebasing
The paths that pmcs passes to the actual compiler will have a different name from what was passed to pmcs itself - these files will contain the actual preprocessed output. For instance:
$ pmcs -profile:foo Bar.cs
Here, Bar.cs
is the original source which needs to be preprocessed. By
default (e.g. -in-place
is not specified), pmcs will generate a file
named ~.pmcs-foo.Bar.cs
which will be passed to the actual compiler.
When the actual compiler compiles these files, their preprocessed names will
end up in the .mdb
symbol files, which is undesirable. By default pmcs will
rebase the symbol files with the original names passed to pmcs.
This can be disabled by passing -skip-mdb-rebase
to pmcs.
Replacements
Three replacement kinds are supported:
Kind | Description |
---|---|
Exact | Only tokens matching exactly are replaced |
Prefix | Tokens starting with a pattern have the matching prefix replaced |
Regex | Tokens matching a regular expression have the matching part replaced |
Additionally, there are two replacement token scopes:
Scope | Description |
---|---|
Global | Perform replacements on any kind of token |
Enum | Perform replacements only on "backing type" tokens for an enum definition |
The "enum" token replacement scope is useful for defining an alternate replacement value for enum backing types when a global replacement value is already defined for the same pattern:
Pattern | Global Replacement | Enum Replacement |
---|---|---|
nint | global::System.Int32 | int |
The enum replacement scope has priority over the global scope.
Replacement Definitions on the Command Line
Replacements can be defined on the command line by specifying one of the two replacement options:
-global-replace:PATTERN=REPLACEMENT
-enum-replace:PATTERN=REPLACEMENT
Where PATTERN
is the pattern to be matched against a token, and REPLACEMENT
is the new value for the matching token or part of the matching token.
To define a Regex replacement on the command line, prefix PATTERN
with /
:
-global-replace:"/^(global::System\.|System\.)?nint=global::System.Int32"
To define a Prefix replacement on the command line, prefix PATTERN
with ^
:
-global-replace:"^MonoTouch=MonoMac"
An exact replacement does not need a prefix to PATTERN
:
-enum-replace:nint=int
Replacement Definitions in an XML Profile
Replacements can also be defined inside a pmcs XML profile with the
<replacement>
element. Each of these elements must have a scope
attribute with a value of either global
or enum
and can contain
child elements named either exact
, prefix
, or regex
with attributes
pattern
and replacement
.
An XML version of the command line replacement definitions above:
<replacements scope="global">
<regex
pattern="^(global::System\.|System\.)?nint"
replacement="global::System.Int32"/>
<prefix pattern="MonoTouch" replacement="MonoMac"/>
</replacements>
<replacements scope="enum">
<exact pattern="nint" replacement="int"/>
</replacements>
Replacement Examples Overview
In the above examples, tokens that are equal to global::System.nint
,
System.nint
, or nint
(as matched by the regular expression replacement)
are replaced with global::System.Int32
, effectively translating a fake
nint
type into a real System.Int32
type.
Because enums can only be backed by certain C# keywords (not types), an
enum-scoped replacement is defined to translate nint
to int
, the C#
keyword for System.Int32
.
Finally, a prefix replacement is used for translating the MonoTouch.*
namespaces into MonoMac.*
namespaces. Prefix replacements are faster
than regular expression replacements.
XML Profiles
XML Profiles provide an alternate means to specifying the compiler
executable, extra compiler options, and replacement definitions. Each
profile must start with a <pmcs>
root element and can contain any
number of the following child elements:
Ignore Paths
<ignore>VALUE</ignore>
element: do not preprocess VALUE
Compiler Configuration
<compiler>
container element. No attributes.
Child elements:
<executable>VALUE</executable>
: specify the compiler executable to beVALUE
<option>VALUE</option>
: appendVALUE
as a command line option to the compiler
Replacements
<replacements scope="global|enum">
container element with scope
attribute; scope
should be either global
or enum
.
See Replacement Definitions in an XML Profile for more detail.
Child elements:
<exact pattern="PATTERN" replacement="REPLACEMENT" />
<prefix pattern="PATTERN" replacement="REPLACEMENT" />
<regex pattern="PATTERN" replacement="REPLACEMENT" />
The child elements specify which kind of replacement to perform.
Includes
<include>PATH</include>
inline another pmcs profile in <include>
order.
where PATH
is relative to the parent directory of the current profile.
Example
<pmcs>
<compiler>
<executable>/usr/local/bin/mcs</executable>
<option>-define:ARCH_32</option>
<option>-sdk:4</option>
</compiler>
<ignore>Compat.cs</ignore>
<replacements scope="global">
<exact pattern="CGSize" replacement="SizeF" />
<exact pattern="CGPoint" replacement="PointF" />
<exact pattern="CGRect" replacement="RectangleF" />
<prefix pattern="MonoTouch" replacement="MonoMac" />
<regex pattern="^(global::System\.|System\.)?nfloat" replacement="global::System.Single" />
<regex pattern="^(global::System\.|System\.)?nint" replacement="global::System.Int32" />
<regex pattern="^(global::System\.|System\.)?nuint" replacement="global::System.UInt32" />
</replacements>
<replacements scope="enum">
<exact pattern="nint" replacement="int" />
<exact pattern="nuint" replacement="uint" />
</replacements>
</pmcs>