docs/Configuration.md
This document describes the configuration system used by Compiler Explorer, which is based on .properties files that
follow a hierarchical structure with inheritance and specialized handling for various property types.
Compiler Explorer uses .properties files located in the etc/config/ directory for all its configuration needs. These
files follow a simple key-value format:
key=value
Leading and trailing whitespace around the value is trimmed.
Comments are lines that start with a hash character, and are not processed:
# This is a comment
key=value # This is also a comment
You can append to an existing string property using the += operator.
Leading whitespace in the appended value is preserved, while trailing whitespace is trimmed.
base.options=-Wall
base.options+= -Wextra
This results in base.options having the value -Wall -Wextra.
[!NOTE] The
+=operator only works for string properties that have already been defined.
Configuration files follow a specific naming pattern:
CATEGORY.ENVIRONMENT.properties
Where:
CATEGORY represents a configuration category (like c++, rust, compiler-explorer, aws)ENVIRONMENT represents where the configuration will be used (like defaults, amazon, local)For example:
c++.defaults.properties - Default C++ configurationc++.amazon.properties - C++ configuration for the Amazon environment (used in production)c++.local.properties - Local C++ configuration (ignored by git, for personal settings)The system loads configuration files in a specific order, creating a cascade of settings. The actual hierarchy used for property resolution, from lowest to highest priority, is:
defaults - Base configuration that applies to all environmentsdev, beta, staging, amazon)dev.linux, staging.darwin)linux, darwin, win32)local - User-specific configuration that overrides all others (can be disabled with the --no-local flag)For example, if you're running on a Linux machine named "myserver" in the "staging" environment, a property would be looked up in this order:
etc/config/category.defaults.propertiesetc/config/category.staging.propertiesetc/config/category.staging.linux.propertiesetc/config/category.linux.propertiesetc/config/category.myserver.propertiesetc/config/category.local.propertiesThis means if the same property is defined in multiple files, the one from the most specific environment will be used.
The hierarchy/cascade only works for top-level properties. Group properties (discussed below) do not inherit across
different environment files. That is, if you define a group property in c++.defaults.properties, but that group is
defined without that property in c++.amazon.properties, the property will not be carried forward to the amazon
environment.
While all properties are stored as strings in the files, the system automatically converts values to appropriate types
using the toProperty function:
Strings - The default type for all properties
compiler.clang.name=Clang
Booleans - Values true, yes, false, no are converted to boolean values
compiler.clang.supportsBinary=true
Numbers - Numeric strings are converted to integers or floats
compiler.clang.timeout=10
Special Version Properties - Properties ending with .version or .semver are never converted to numbers, even
if they look like numbers. This preserves version formatting with leading zeros or other special characters:
compiler.gcc123.version=9.0.0 # Remains the string "9.0.0" instead of becoming a number
Many properties in Compiler Explorer represent lists of values. These use specific separators:
Colon-separated lists (:) - Most commonly used for lists of identifiers, compiler names, etc.
compilers=gcc:clang:msvc
Pipe-separated lists (|) - Used for argument lists, particularly when options might contain colons
compiler.clang.demanglerArgs=-n|-C|--no-verbose
Compilers are configured using properties with the compiler.ID prefix:
compiler.gcc.name=GCC
compiler.gcc.exe=/usr/bin/gcc
compiler.gcc.options=-Wall
A key feature of the configuration system is the ability to define groups of compilers with shared settings using &
syntax:
compilers=&gcc:&clang:specific_compiler
group.gcc.compilers=gcc7:gcc8:gcc9
group.gcc.groupName=GCC
group.gcc.supportsBinary=true
group.clang.compilers=clang9:clang10
group.clang.groupName=Clang
group.clang.intelAsm=-mllvm --x86-asm-syntax=intel
In this example:
compilers list includes two groups (&gcc and &clang) and one individual compilersupportsBinary or intelAsm) are inherited by all compilers in that groupGroups can contain other groups by using the & syntax within a group's compilers list:
group.newer.compilers=&clang:&gcc
group.newer.groupName=Modern Compilers
Properties are inherited from groups to individual compilers. If both a group and a compiler define the same property, the compiler's value takes precedence. This allows for group-wide defaults with compiler-specific overrides. There are some notable exceptions to this rule: some unique-per-compiler properties are not inherited from groups, but we hope to fix this. See this GitHub issue.
Common configuration keys include:
| Key Name | Type | Description |
|---|---|---|
| name | String | Human-readable name displayed to users |
| exe | Path | Path to the executable |
| options | String | Default compiler options |
| compilerType | String | Refers to the handler class in lib/compilers/*.ts |
| intelAsm | String | Flags for Intel assembly syntax |
| supportsX | Boolean | Capability flags for various features |
| versionFlag | String | Flag to pass to compiler to get version |
| demanglerArgs | String | Arguments for the demangler (pipe-separated) |
| objdumperArgs | String | Arguments for the object dumper (pipe-separated) |
| instructionSet | String | Default instruction set for the compiler |
Some properties support variable substitution to make configuration more flexible. The most common variables are:
${exePath}: Replaced with the directory path of the compiler executable
ldPath=/opt/compiler-explorer/lib/|${exePath}/../lib/
${ceToolsPath}: Replaced with the path to the Compiler Explorer tools directory
demangler=${ceToolsPath}/demangler
Environment variables can be configured using a special format:
envVars=VAR1=value1:VAR2=value2
This is parsed and converted into environment variable key-value pairs that are passed to the compiler when it's executed.
Multiple types of path lists exist in the system, mainly using two separator styles:
Colon-separated: Used for general lists (compilers, versions, etc.)
compilers=gcc:clang:msvc
Pipe-separated: Used for path lists and command arguments
ldPath=/path/to/lib1|/path/to/lib2
demanglerArgs=-n|-C|--no-verbose
Note that path-style properties often support variable substitution as shown above.
You can enable detailed debugging of property resolution by using the --prop-debug flag when starting Compiler
Explorer. This shows every property lookup, including where properties are being overridden and which configuration
source they come from.
Compiler Explorer supports defining remote compilers using a special syntax in the configuration:
compilers=local1:local2:remote@hostname:port
When a compiler ID contains the @ symbol followed by a hostname and port, it is interpreted as a remote compiler. This
allows running compilers on separate machines and accessing them through the main Compiler Explorer instance.
The system has built-in detection for "orphaned" properties - configurations for compilers or groups that are not referenced anywhere. This helps maintain configuration cleanliness by identifying unused configuration entries.
The configuration system is implemented primarily in the following files:
lib/properties.ts - Core implementation of the properties systemlib/properties.interfaces.ts - TypeScript interfaces for the properties systemlib/compiler-finder.ts - Handles compiler discovery and group expansionlib/utils.ts - Contains property value conversion functionsIf you need to troubleshoot configuration issues, you can run Compiler Explorer with debug output:
make EXTRA_ARGS='--prop-debug' dev
This will show detailed logs about property resolution, including which properties are being overridden and from which source.