xamarin-macios/tools/pmcs
Rolf Bjarne Kvinge 084e691be2 [src] Make sure to always set all variants of our conditional compilation symbols. (#986)
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.
2016-10-13 15:10:24 +02:00
..
CSharp Build the platform assemblies. 2016-04-24 14:47:26 -04:00
profiles Build the platform assemblies. 2016-04-24 14:47:26 -04:00
tests Build the platform assemblies. 2016-04-24 14:47:26 -04:00
.gitignore Build the platform assemblies. 2016-04-24 14:47:26 -04:00
BuiltinProfiles.cs [src] Make sure to always set all variants of our conditional compilation symbols. (#986) 2016-10-13 15:10:24 +02:00
Driver.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Makefile Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Makefile.frag Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Parser.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Preprocessor.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Profile.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
README.md Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Replacement.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Settings.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
Timer.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
XamarinPreprocessorVisitor.cs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
pmcs Build the platform assemblies. 2016-04-24 14:47:26 -04:00
pmcs.csproj Build the platform assemblies. 2016-04-24 14:47:26 -04:00

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 be VALUE
  • <option>VALUE</option>: append VALUE 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>