PMCPP(1)
π PMCPP(1) β the manual page, but make it make sense π
General Commands Manual Β· pmcpp Β· the cutest little preprocessor you ever did meet
okay bestie, sit down, hydrate, and let me tell you about pmcpp β¨
πΈ NAME πΈ
pmcpp β a simple preprocessor for the Performance Co-Pilot π«Ά
π SYNOPSIS π
pmcpp [-Prs?] [-D name[=value] ...] [-I dir ...] [[infile] [outfile]]
β¨ DESCRIPTION β¨
So pmcpp is this very simple pre-processor that was originally built to mess with Performance Metric Name Space (PMNS) files for the Performance Co-Pilot (PCP) β iconic origin story, honestly β but then it got generalized to also do conditional blocks, include-file processing, in-line shell command execution, and macro substitution for arbitrary files. glow-up of the century π
Where you'll actually catch it in the wild: it's most commonly used internally to process the PMNS file(s) after pmLoadNameSpace(3) or pmLoadASCIINameSpace(3) gets called, and to pre-process the config files for pmlogger(1). iykyk π
Here's the flow, bestie:
- Input lines get read from infile β or from standard input if infile isn't specified.
- They get processed.
- They get written to outfile β or to standard output if outfile isn't specified.
All C-style comments of the form /* ... */ are stripped straight out of the input stream. gone. bye. π
Also important: there are no predefined macros for pmcpp β nope, not one β although you can define macros on the command line with the -D option, where name and value have to follow the exact same rules as the #define directive described down below. no cap π
pmcpp accepts the following directives in the input stream (just like cpp(1)) π§
#include "filename"or#include <filename>
Either way, the directory search path for filename tries filename first, then the directory of the command line infile (if there is one), followed by any directories named in -I command line arguments, and finally the $PCP_VAR_DIR/pmns directory β that last one is for backwards compatibility with earlier versions of pmcpp and the implied use from pmLoadASCIINameSpace(3). Also, #include directives may be nested, up to a maximum depth of 5. five. that's the limit, bestie, don't push it π
#shell "command"or#shell 'command'
The shell command gets executed and its standard output is inserted into the stream of data that pmcpp is processing. Functionally this is basically a #include directive, except the input lines come from a command instead of a file. The #shell directive is most useful for including or excluding #define or #undef directives based on run-time logic in the command. chef's kiss π
#define name valueor#define name "value"or#define name 'value'
Defines a value for the macro name, which must be a valid C-style name β so leading alphabetic or underscore, followed by zero or more alphanumerics or underscores. value is optional (and defaults to an empty string). There is no character escape mechanism, but either single quotes or double quotes may be used to define a value with special characters or embedded horizontal white space (no newlines, okay?). πΈ
#undef name
Removes the macro definition, if any, for name. gone girl π
#ifdef name...#endifor#ifndef name...#endif
The enclosing lines get stripped or included, depending on whether the macro name is defined or not.
#else
Within a #ifdef or #ifndef block, #else may be used to delimit the lines to be included if the preceding ``if'' condition is false.
Macro substitution happens by breaking the input stream into words separated by white space or characters that are not valid in a macro name β i.e. not alphanumeric and not underscore. Each word gets checked, and if it matches a macro name, the word gets replaced by the macro value. Otherwise the word is left alone. simple as that π¦
There is generally one output line for each input line, although the line may be empty if the text got stripped due to comment handling or conditional directives. And when there's a change in the input stream, an additional output line is generated of the form:
# lineno "filename"
which is telling you that the following line of output corresponds to line number lineno of the input file filename. cute little receipt, right? π
π OPTIONS π
The available command line options are:
-D name[=value],--define=name[=value]β Defines a macro with an optional value, as described earlier. β¨-I dir,--include=dirβ An additional directory to search for include files. ποΈ-Pβ Suppresses the generation of the linemarker lines, described above. no more receipts π-s,--shellβ Changes the expected input style from C-like to shell-like (where#is a comment prefix). This forces the following changes inpmcppbehaviour:- The control prefix character changes from
#to%, so for example%includeinstead of#include, and%ifdefinstead of#ifdef. π - No C-style comment stripping is performed. π
- The control prefix character changes from
-r,--restrictβ Provide finer control of macro expansion β this option restricts macro substitution to words that match the patterns#nameor#{name}or, if-sis specified, then%nameor%{name}. In this mode, the macro name alone in the input stream will never be expanded, however in control lines (like#ifdef) the macro name should appear alone, without the prefix character or the curly braces (refer to the EXAMPLES below). π-?,--helpβ Display usage message and exit. π«Ά
Important cpp(1) features that are not supported by pmcpp include:
- Macros with parameters β the
pmcppmacros support only parameterless string substitution. π #if expr...#endif- Nested use of
#ifdefor#ifndef. - Stripping C++ style comments, as in
// comment. - Error recovery β the first error encountered by
pmcppwill be fatal. π cpp(1)command line options like-o,-W,-U, and-x.
πΈ EXAMPLES πΈ
okay bestie, this is the part where it all clicks, i promise π
example 1 β just plain pmcpp, no flags, vibing
command:
pmcpp
so if you feed it this on stdin:
#define MYDOMAIN 27
root {
foo MYDOMAIN:0:0
}
you get this back:
# 1 "<stdin>"
root {
foo 27:0:0
}
see how MYDOMAIN got swapped for 27? the preprocessor ate the #define line and dropped that little # 1 "<stdin>" breadcrumb in its place β¨
for the next two examples, imagine there's a file called frequencies and it contains exactly these lines:
%define dk_freq 1min
%define cpu_freq '15 sec'
example 2 β pmcpp -rs, no extra defines
command:
pmcpp -rs
input:
# get logging frequencies
# e.g. dk_freq macro
%include "frequencies"
log mandatory on %dk_freq {
disk.dev
}
# note no %want_cpu here
%ifdef want_cpu
%define cpu_pfx 'kernel.all.cpu.'
log mandatory on %cpu_freq {
%{cpu_pfx}user
%{cpu_pfx}sys
}
%endif
output:
# get logging frequencies
# e.g. dk_freq macro
log mandatory on 1min {
disk.dev
}
# note no %want_cpu here
notice how %include "frequencies" pulled in dk_freq so %dk_freq became 1min π and because nobody defined want_cpu, the whole %ifdef want_cpu block just... poofed π¨
example 3 β pmcpp -rs -D want_cpu, now we're cooking
command:
pmcpp -rs -D want_cpu
input (same as before, no cap):
# get logging frequencies
# e.g. dk_freq macro
%include "frequencies"
log mandatory on %dk_freq {
disk.dev
}
# note no %want_cpu here
%ifdef want_cpu
%define cpu_pfx 'kernel.all.cpu.'
log mandatory on %cpu_freq {
%{cpu_pfx}user
%{cpu_pfx}sys
}
%endif
output:
# get logging frequencies
# e.g. dk_freq macro
log mandatory on 1min {
disk.dev
}
# note no %want_cpu here
log mandatory on 15 sec {
kernel.all.cpu.user
kernel.all.cpu.sys
}
ok so NOW want_cpu is defined, so the %ifdef block stays in, %cpu_freq becomes 15 sec, and %{cpu_pfx} becomes kernel.all.cpu. β literally everything slotted into place π
π PCP ENVIRONMENT π
so PCP has this whole thing where environment variables starting with PCP_ are the ones that parameterize the file and directory names PCP uses π«Ά
every time you install it, the file /etc/pcp.conf holds the local values for all those variables. and if you wanna point at a different config file instead, you use the $PCP_CONF variable β full details live over in pcp.conf(5).
and if you're looking for the environment variables that affect PCP tools specifically (not the file/dir names), those are documented in pmGetOptions(3) π
π SEE ALSO π
go read these next, fr fr:
and that's the whole page bestie, you made it to the end π this is the Performance Co-Pilot PMCPP(1) manual page β iconic source, iconic version, and honestly the date is giving "whenever you're reading this" energy π now go preprocess something and slay β¨
π¦ where this page comes from
- arch rolling: pcp 7.2.2-2 Β· GPL-2.0-or-later AND LGPL-2.1-or-later AND CC-BY-3.0
- fedora 43: pcp-doc 7.2.2-1.fc43
- fedora 43: pcp-doc 7.2.2-2.fc43 Β· GPL-2.0-or-later AND CC-BY-3.0
- fedora 44: pcp-doc 7.2.2-1.fc44
- fedora 44: pcp-doc 7.2.2-2.fc44 Β· GPL-2.0-or-later AND CC-BY-3.0
- Copyright (c) 2011 Ken McDonell. All Rights Reserved
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms