You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
P4C is a reference compiler for the P4 programming language.
It supports both P4-14 and P4-16; you can find more information about P4
here and the specifications for both versions of the language
here.
One fact attesting to the level of quality and completeness of P4C's
code is that its front-end code, mid-end code, and P4C-graphs back end
are used as the basis for at least one commercially supported P4
compiler.
P4C is modular; it provides a standard frontend and midend which can be combined
with a target-specific backend to create a complete P4 compiler. The goal is to
make adding new backends easy.
Sample Backends in P4C
P4C includes seven sample backends, catering to different target architectures and use cases:
p4c-bm2-ss: can be used to target the P4 simple_switch written using
the BMv2 behavioral model,
p4test: a source-to-source P4 translator which can be used for
testing, learning compiler internals and debugging,
p4c-graphs: can be used to generate visual representations of a P4 program;
for now it only supports generating graphs of top-level control flows, and
p4c-ubpf: can be used to generate eBPF code that runs in user-space.
p4tools: a platform for P4 test utilities, including a test-case generator for P4 programs.
Sample command lines:
Compile P4_16 or P4_14 source code. If your program successfully
compiles, the command will create files with the same base name as the
P4 program you supplied, and the following suffixes instead of the
.p4:
a file with suffix .p4i, which is the output from running the
preprocessor on your P4 program.
a file with suffix .json that is the JSON file format expected by
BMv2 behavioral model simple_switch.
By adding the option --p4runtime-files <filename>.txt as shown in
the example commands below, P4C will also create a file
<filename>.txt. This is a text format "P4Info" file, containing a
description of the tables and other objects in your P4 program that
have an auto-generated control plane API.
All of these commands take the --help argument to show documentation
of supported command line options. p4c --target-help shows the
supported "target, arch" pairs.
Check syntax of P4_16 or P4_14 source code, without limitations that
might be imposed by any particular compiler back end. There is no
output for these commands other than error and/or warning messages.
If you cannot use a repository to install P4C, you can download the .deb file
for your release and install it manually. You need to download a new file each
time you want to upgrade P4C.
The cmake command takes the following optional arguments to
further customize the build (see file CMakeLists.txt for the full list):
-DCMAKE_BUILD_TYPE=Release|Debug -- set CMAKE_BUILD_TYPE to
Release or Debug to build with optimizations or with debug
symbols to run in gdb. Default is Release.
-DCMAKE_INSTALL_PREFIX=<path> -- set the directory where
cmake --build build --target install installs the compiler. Defaults to /usr/local.
-DENABLE_DOCS=ON|OFF. Build documentation. Default is OFF.
-DENABLE_GC=ON|OFF. Enable the use of the garbage collection
library. Default is ON.
-DENABLE_GTESTS=ON|OFF. Enable building and running GTest unit tests.
Default is ON.
-DP4C_USE_PREINSTALLED_ABSEIL=ON|OFF. Try to find a system version of Abseil instead of a fetched one. Default is OFF.
-DP4C_USE_PREINSTALLED_MULTIPRECISION=ON|OFF. Use installed Multiprecision headers and their matching Boost dependencies instead of fetching standalone Multiprecision. Default is OFF.
-DP4C_USE_PREINSTALLED_PROTOBUF=ON|OFF. Try to find a system version of Protobuf instead of a CMake version. Default is OFF.
-DENABLE_ABSEIL_STATIC=ON|OFF. Enable the use of static abseil libraries. Default is ON. Only has an effect when P4C_USE_PREINSTALLED_ABSEIL is enabled.
-DENABLE_PROTOBUF_STATIC=ON|OFF. Enable the use of static protobuf libraries. Default is ON.
Only has an effect when P4C_USE_PREINSTALLED_PROTOBUF is enabled.
-DENABLE_MULTITHREAD=ON|OFF. Use multithreading. Default is
OFF.
-DBUILD_LINK_WITH_GOLD=ON|OFF. Use Gold linker for build if available.
-DBUILD_LINK_WITH_LLD=ON|OFF. Use LLD linker for build if available (overrides BUILD_LINK_WITH_GOLD).
-DENABLE_LTO=ON|OFF. Use Link Time Optimization (LTO). Default is OFF.
-DENABLE_WERROR=ON|OFF. Treat warnings as errors. Default is OFF.
-DCMAKE_UNITY_BUILD=ON|OFF . Enable unity builds for faster compilation. Default is OFF.
If adding new targets to this build system, please see
instructions.
(Optional) Install the compiler and the P4 shared headers globally.
sudo cmake --build build --target install
The compiler driver p4c and binaries for each of the backends are
installed in /usr/local/bin by default; the P4 headers are placed in
/usr/local/share/p4c.
You're ready to go! You should be able to compile a P4-16 program for BMV2
using:
If you plan to contribute to P4C, you'll find more useful information
here.
Dependencies
Ubuntu 22.04 and Ubuntu 24.04 are the officially supported platforms for P4C.
There's also unofficial support for macOS, including Apple Silicon. Other
platforms are untested; you can try to use them, but YMMV.
A C++20 compiler. P4C is built with CMAKE_CXX_STANDARD 20.
git for version control
CMake 3.16.3 or higher
Boehm-Weiser garbage-collector C++ library
GNU Bison and Flex for the parser and lexical analyzer generators.
Google Protocol Buffers v3.25.3 or higher for control plane API generation
Boost.Multiprecision library for arbitrary precision arithmetic
Python 3 and uv for scripting and running tests
Optional: Documentation generation requires Doxygen (1.13.2) and Graphviz (2.38.0 or higher).
Backends may have additional dependencies. The dependencies for the backends
included with P4C are documented here:
P4C also depends on Google Protocol Buffers (Protobuf). P4C requires version
3.0 or higher, so the packaged version provided in Ubuntu 22.04 should
work. However, P4C typically installs its own version of Protobuf using CMake's FetchContent module
(at the moment, 3.25.3). If you are experiencing issues with the Protobuf version shipped with your OS distribution, we recommend that to install Protobuf 3.25.3 from source. You can find instructions
here.
After cloning Protobuf and before you build, check-out version 3.25.3:
git checkout v3.25.3
Please note that while all Protobuf versions newer than 3.0 should work for
P4C itself, you may run into trouble with Abseil, some extensions and other p4lang
projects unless you install version 3.25.3.
P4C also depends on Google Abseil library. This library is also a pre-requisite for Protobuf of any version newer than 3.21. Therefore the use of Protobuf of suitable version automatically fulfils Abseil dependency. P4C typically installs its own version of Abseil using CMake's FetchContent module (Abseil LTS 20240722.1 at the moment).
CMake
P4C requires a CMake version of at least 3.16.3 or higher. On older systems, a newer version of CMake can be installed using pip3 install --user cmake==3.16.3, but there is no guarantee that this will lead to a successful build.
By default, Homebrew doesn't link programs into /usr/local/bin if
they would conflict with a version provided by the base system. This
includes Bison, since an older version ships with macOS. cmake --build build --target check
depends on the newer Bison we just installed from Homebrew
(see #83), so you'll want
to add it to your $PATH one way or another. One simple way to do
that is to request that Homebrew link it into /usr/local/bin:
brew link --force bison
Optional documentation building tools:
Download and install the Doxygen 1.13.2 DMG file from here.
Homebrew offers a protobuf formula. It installs version 3.2, which should
work for P4C itself but may cause problems with some extensions. It's
preferable to use the version of Protobuf which is supplied with CMake's fetchcontent (3.25.3).
The protobuf formula requires the following CMake variables to be set,
otherwise CMake does not find the libraries or fails in linking. It is likely
that manually installed Protobuf will require similar treatment.
P4c relies on BDW garbage collector
to manage its memory. By default, the P4C executables are linked with
the garbage collector library. When the GC causes problems, this can
be disabled by setting ENABLE_GC cmake option to OFF. However,
this will dramatically increase the memory usage by the compiler, and
may become impractical for compiling large programs. Do not disable
the GC, unless you really have to. We have noticed that this may be
a problem on MacOS.
Crash dumps
P4c will use libbacktrace
to produce readable crash dumps if it is available. This is an optional
dependency; if it is not available everything should build just fine, but
crash dumps will not be very readable.
Development tools
There is a variety of design and development documentation here.
We recommend using clang++ with no optimizations for speeding up
compilation and simplifying debugging.
We recommend installing a new version of gdb,
because older gdb versions do not always handle C++11 or newer correctly.
We recommend exuberant ctags for navigating source code in Emacs and vi. sudo apt-get install exuberant-ctags. The CMake targets ctags and etags generate
tags for vi and Emacs respectively via cmake --build build --target ctags or
cmake --build build --target etags. (Make sure that you are using the correct
version of ctags; there are several competing programs with the same name in
existence.)
To build code documentation, after installing Doxygen and the other
required packages:
# Starting from root directory of your copy of p4c repocd docs/doxygen
doxygen doxygen.cfg
The HTML output is available in
docs/doxygen/build/html/index.html.
Git setup
Occasionally formatting commits are applied to P4C. These pollute the git history. To ignore these commits in git blame, run this command
git config blame.ignoreRevsFile .git-blame-ignore-revs
The P4C code base is subject to a series of linter checks which are checked by CI. To avoid failing these checks and wasting unnecessary CI cycles and resources, you can install git commit hooks by running
./tools/install_git_hooks.sh
These commit hooks will run on every commit and check the files you are planning to commit with cpplint and clang-format.
Docker
A Dockerfile is included. You can generate an image which contains a copy of P4C
in /p4c/build by running:
docker build -t p4c .
On some platforms Docker limits the memory usage of any container, even
containers used during the docker build process. On macOS in particular the
default is 2GB, which is not enough to build P4C. Increase the memory limit to
at least 4GB via Docker preferences or you are likely to see "internal compiler
errors" from GCC which are caused by low memory.
We run continuous integration to ensure this works with the latest version of
Bazel.
We also provide a p4_library rule for invoking
P4C during the build process of 3rd party Bazel projects.
See bazel/example for an example of how to use or extend P4C in
your own Bazel project. You may use it as a template to get you started.
Build system
The build system is based on cmake. This section describes how it can be customized.
Defining new CMake targets
When building a new backend target, add it into the development tree in the
extensions subdirectory. The cmake-based build system will automatically include
it if it contains a CMakeLists.txt file.
For a new backend, the cmake file should contain the following rules:
IR definition files
Backend specific IR definition files should be added to the global list
of IR_DEF_FILES as they are processed together with the core IR files.
Use the following rule:
set (IR_DEF_FILES ${IR_DEF_FILES} ${MY_IR_DEF_FILES} PARENT_SCOPE)
where MY_IR_DEF_FILES is a list of file names with absolute path
(for example, use ${CMAKE_CURRENT_SOURCE_DIR}).
If in addition you have additional supporting source files, they
should be added to the ir sources, as follows:
The P4C CMakeLists.txt will use that name to figure the full path of the files to lint.
The precise version of the formatting tools is specified in pyproject.toml, use uv run to run the tools with the correct version:
uv run cmake -S . -B build
Check C++ and Python formatting:
uv run cmake --build build --target clang-format black isort
Apply formatting fixes:
uv run cmake --build build --target \
clang-format-fix-errors black-fix-errors isort-fix-errors
To run just one formatter, specify only its target.
If an existing build still uses a system-installed formatter
CMake caches the paths to formatter executables when you first configure a build.
If you configured before installing the tools above, the build may still use a
system-installed formatter with a different version. Use this command to clear the cached paths and reconfigure the build:
cpplint, clang-format, and black/isort run as checks as port of P4C's continuous integration process. To make sure that these tests pass, we recommend installing the appropriate git hooks. This can be done by running
./tools/install_git_hooks.sh
clang-format, cpplint, and black/isort checks will be enforced on every branch commit. In cases where checks are failing but the commit is sound, one can bypass the hook enforcement using git commit --no-verify.
Target
Define a target for your executable. The target should link against
the core P4C_LIBRARIES and P4C_LIB_DEPS. P4C_LIB_DEPS are
package dependencies. If you need additional libraries for your
project, add them to P4C_LIB_DEPS.
In addition, your target should depend on the genIR target, since
you need all the IR generation to happen before you start compiling
your backend. If you chose to have your backend as a library (seem the
backends/bmv2 example), the library should depend on genIR, and
there is no longer necessary for your executable to depend on it.
We implemented support equivalent to the automake cmake --build build --target check rules.
All tests should be included in cmake --build build --target check and in addition, we support
cmake --build build --target check-* rules. To enable this support, add the following rules:
set(MY_DRIVER <driver or compiler executable>)
set (MY_TEST_SUITES
${P4C_SOURCE_DIR}/testdata/p4_16_samples/*.p4
${P4C_SOURCE_DIR}/testdata/p4_16_errors/*.p4
)
set (MY_XFAIL_TESTS
testdata/p4_16_errors/this_test_fails.p4
)
p4c_add_tests("mybackend" ${MY_DRIVER} "${MY_TEST_SUITES}" "${MY_XFAIL_TESTS}")
In addition, you can add individual tests to a suite using the following macro:
When making changes to P4C, it is sometimes useful to be able to run
the tests while overwriting the expected output files that are saved
in this repository. One such situation is when your changes to P4C
cause the names of compiler-generated local variables to change. To
force the expected output files to be rewritten while running the
tests, assign a value to the shell environment variable
P4TEST_REPLACE. Here is one example Bash command to do so:
Define rules to install your backend. Typically you need to install
the binary, the additional architecture headers, and the configuration
file for the P4C driver.
Issues with the compiler are tracked on
GitHub. Before opening a new
issue, please check whether a similar issue is already opened. Opening
issues and submitting a pull request with fixes for those issues is
much appreciated.
In addition to the list of issues on Github, there are a number of
currently unsupported features listed below:
Frontend
P4_14 features not supported in P4_16
extern/blackbox attributes -- there is support for carrying them in
the IR, but they are lost if P4_16 code is output. Backends can
access them from the IR