Status
RFC 0001
Drafted "v0.0.2"
Related PRs:
#734
Abstract
This RFC proposes a standardized mechanism for defining and propagating runtime environment configuration across MetaCall loaders and ports. The mechanism introduces a declarative environment profile format that centralizes runtime home paths, search paths, and initialization requirements, replacing the current pattern of duplicative platform-specific code in each loader and port implementation.
Motivation
The Problem
The current MetaCall architecture requires each loader and port to implement its own platform-specific initialization logic. Consider the changes introduced in PR #734 to fix Windows Python initialization and mainly it's a repeated problem in CIs and Infrastructure:
- py_loader adds
py_loader_impl_initialize_python_home() to set PYTHONHOME before Py_InitializeEx()
- rs_port adds
ensure_python_home() as a fallback for backward compatibility
This pattern creates several issues:
- Code duplication: Each loader must reimplement the same initialization patterns for its target runtime
- Platform-specific pollution:
#if defined(WIN32) blocks scattered across the codebase
- Maintenance burden: When runtime initialization logic changes, it must be updated in multiple places
- Inconsistent behavior: Different loaders may handle the same initialization scenarios differently
The Opportunity
Other polyglot runtimes and version managers have solved similar problems through declarative profile systems:
- SDKMAN uses
~/.sdkman/etc/config and ~/.sdkman/candidates/ layout
- Conda uses
environment.yml with explicit channel and dependency declarations
- GraalVM uses
META-INF/native-image/ with structured metadata
- asdf uses
.tool-versions for project-level runtime specification
MetaCall already has a configuration system (loader.json.in, global.json). The opportunity is to extend this with a dedicated runtime environment profile that:
- Declares runtime requirements per language
- Provides platform-aware path resolution
- Enables automatic environment variable propagation
- Supports both system-wide and per-project profiles
Delimma
A developer installs MetaCall on a fresh Linux system. They want to run Python and Node scripts that call each other. With the current system, they must:
- Manually set
LOADER_LIBRARY_PATH
- Manually set
SERIAL_LIBRARY_PATH
- Manually configure
PYTHONHOME and NODE_PATH
- Ensure these variables are set consistently across all shell sessions
With the proposed system, they run:
source /etc/profile.d/metacall.sh
And the profile script automatically sets all necessary variables based on the installed runtime configuration.
Specification
1. Terminology
| Term |
Definition |
| MREP |
MetaCall Runtime Environment Profile, the declarative configuration format |
| Runtime Profile |
A JSON file containing MREP declarations |
| Runtime Home |
The base directory containing a language runtime installation |
| Profile Directory |
The directory containing runtime profiles and associated metadata |
| Port |
A language binding that loads the MetaCall runtime (Rust, Go, Java, C#, etc.) |
| Loader |
A plugin that embeds a language runtime (Python, Node, Ruby, etc.) |
2. Profile Format
The MREP format uses JSON with the following schema:
{
"$schema": "https://metacall.io/schemas/mrep-v1.json",
"meta": {
"version": "1.0.0",
"schema": "https://metacall.io/schemas/mrep-v1.json",
"generated": "2024-01-15T10:30:00Z"
},
"runtimes": {
"<language>": {
"home": "<absolute-path-or-variable-reference>",
"search_paths": ["<path>", "<path>"],
"environment": {
"<VAR_NAME>": "<value>"
},
"options": {
"<option>": "<value>"
}
}
},
"defaults": {
"loaders_path": "<path>",
"scripts_path": "<path>",
"config_path": "<path>"
}
}
2.1 Field Definitions
| Field |
Type |
Description |
meta.version |
string |
MREP format version (semver) |
meta.schema |
string |
JSON Schema URI for validation |
meta.generated |
string |
ISO 8601 timestamp of profile generation |
runtimes.<language>.home |
string |
Runtime home directory or variable reference |
runtimes.<language>.search_paths |
array |
Platform-specific library search paths |
runtimes.<language>.environment |
object |
Environment variables to set before initialization |
runtimes.<language>.options |
object |
Loader-specific configuration options |
defaults.loaders_path |
string |
Default directory for loader plugins |
defaults.scripts_path |
string |
Default directory for scripts |
defaults.config_path |
string |
Default path to global configuration |
2.2 Variable References
The home field supports variable references for flexible path resolution:
| Reference |
Expansion |
Example |
$METACALL_PREFIX |
Installation prefix |
/usr/local |
$METACALL_HOME |
Profile directory parent |
/etc/metacall |
$ORIGIN |
Loader binary directory |
Platform-specific |
<os-family> |
Platform-specific path |
Windows: %LOCALAPPDATA%\MetaCall |
2.3 Example Profiles
Linux System Installation:
{
"meta": {
"version": "1.0.0",
"schema": "https://metacall.io/schemas/mrep-v1.json",
"generated": "2024-01-15T10:30:00Z"
},
"runtimes": {
"python": {
"home": "$METACALL_PREFIX/lib/metacall/runtimes/python",
"search_paths": [
"$METACALL_PREFIX/lib",
"$METACALL_PREFIX/lib/metacall/runtimes/python/lib"
],
"environment": {
"PYTHONIOENCODING": "utf-8",
"PYTHONDONTWRITEBYTECODE": "1"
}
},
"ruby": {
"home": "$METACALL_PREFIX/lib/metacall/runtimes/ruby",
"search_paths": [
"$METACALL_PREFIX/lib",
"$METACALL_PREFIX/lib/metacall/runtimes/ruby/lib"
]
},
"node": {
"home": "$METACALL_PREFIX/lib/metacall/runtimes/node",
"search_paths": [
"$METACALL_PREFIX/lib"
]
}
},
"defaults": {
"loaders_path": "$METACALL_PREFIX/lib/metacall/loaders",
"scripts_path": "$METACALL_PREFIX/share/metacall/scripts",
"config_path": "$METACALL_PREFIX/etc/metacall/global.json"
}
}
Windows Installation:
{
"meta": {
"version": "1.0.0",
"schema": "https://metacall.io/schemas/mrep-v1.json",
"generated": "2024-01-15T10:30:00Z"
},
"runtimes": {
"python": {
"home": "%LOCALAPPDATA%\\MetaCall\\runtimes\\python",
"search_paths": [
"%LOCALAPPDATA%\\MetaCall\\lib",
"%LOCALAPPDATA%\\MetaCall\\runtimes\\python"
],
"environment": {
"PYTHONHOME": "%LOCALAPPDATA%\\MetaCall\\runtimes\\python",
"PYTHONIOENCODING": "utf-8"
}
}
},
"defaults": {
"loaders_path": "%LOCALAPPDATA%\\MetaCall\\loaders",
"scripts_path": "%LOCALAPPDATA%\\MetaCall\\scripts",
"config_path": "%LOCALAPPDATA%\\MetaCall\\config\\global.json"
}
}
2.4 Python Path Matrix
The table below captures the current Python-related paths used by MetaCall as requested.
| Install method |
MetaCall library discovery (Python port) |
Python runtime root |
Python module path / PYTHONPATH |
MetaCall configuration path |
Loader paths / env profile |
| Linux distributable tarball (Guix-based) |
/gnu/lib/libmetacall(.so) (also searched by Python/Node/Ruby ports via /gnu/lib) |
Guix Python runtime in /gnu/store/..., exposed through /gnu profile |
PYTHONPATH=/gnu/lib/python<major.minor>/site-packages (from /gnu/etc/profile); installer wrapper also appends lib-dynload |
CONFIGURATION_PATH=/gnu/configurations/global.json |
LOADER_LIBRARY_PATH=/gnu/lib, SERIAL_LIBRARY_PATH=/gnu/lib, DETOUR_LIBRARY_PATH=/gnu/lib, PORT_LIBRARY_PATH=/gnu/lib |
macOS Homebrew formula (metacall/homebrew) |
/opt/homebrew/lib/libmetacall(.dylib) (arm64) or /usr/local/lib/libmetacall(.dylib) (intel) |
Homebrew Python formula (python@3.x) via python.opt_* (no fixed PYTHONHOME) |
Wrapper exports PYTHONPATH=${PREFIX}/lib/python:${PYTHONPATH:-}; formula tests also use ${HOMEBREW_PREFIX}/lib/python |
Wrapper exports CONFIGURATION_PATH=${PREFIX}/configurations/global.json |
Wrapper exports SERIAL_LIBRARY_PATH, DETOUR_LIBRARY_PATH, PORT_LIBRARY_PATH to ${PREFIX}/lib (note: current formula uses LOADER_LIBRARY, not LOADER_LIBRARY_PATH) |
Linux DEB/RPM package from core releases (apt/dpkg) |
Default package build currently targets /usr/local/lib/libmetacall(.so) |
System Python from package dependencies (not a bundled runtime folder) |
No package-managed PYTHONPATH export by default; relies on system Python layout |
Build/install default resolves to /usr/local/share/metacall/configurations/global.json (or configured prefix equivalent) |
Compile-time defaults point loader/serial/detour/port install paths to <prefix>/lib |
Windows distributable installer script (install.ps1 + zip asset) |
Port default search root is %LOCALAPPDATA%\MetaCall\metacall and recursively finds metacall(.dll) (currently stored under ...\lib) |
%LOCALAPPDATA%\MetaCall\metacall\runtimes\python (PYTHONHOME) |
PIP_TARGET=%LOCALAPPDATA%\MetaCall\metacall\runtimes\python\Lib\site-packages; runtime PATH includes Python/Scripts/site-packages bin |
CONFIGURATION_PATH=%LOCALAPPDATA%\MetaCall\metacall\configurations\global.json |
LOADER_LIBRARY_PATH, SERIAL_LIBRARY_PATH, DETOUR_LIBRARY_PATH, PORT_LIBRARY_PATH all exported to %LOCALAPPDATA%\MetaCall\metacall\lib |
Windows installer note: current core packaging generators are NSIS;ZIP (not MSI). The Windows one-line installer consumes metacall-tarball-win-<arch>.zip assets from metacall/distributable-windows.
Implication for MREP abstraction: Python path resolution needs at least three explicit layers:
- User override layer (
METACALL_INSTALL_PATH, PYTHONHOME, etc.)
- Installer/profile layer (distributable wrappers or generated shell/profile scripts)
- Platform fallback layer (compiled install prefix + known platform discovery roots)
This preserves compatibility with existing installs while removing per-port/per-loader hardcoded path duplication.
3. Profile Discovery
3.1 Discovery Order
The system MUST search for profiles in the following order, with earlier entries taking precedence:
$METACALL_ENVIRONMENT - Explicit profile path via environment variable
$METACALL_HOME/environment.json - User-level profile
$METACALL_PREFIX/etc/metacall/environment.json - System installation profile
- Embedded default profile in loader library
3.2 Path Resolution
Variable references in profiles MUST be resolved according to the following rules:
| Variable |
Source |
Example |
$METACALL_PREFIX |
CMake CMAKE_INSTALL_PREFIX or equivalent |
/usr/local |
$METACALL_HOME |
User-configurable, defaults to $HOME/.metacall |
~/.metacall |
$ORIGIN |
Resolved at runtime to loader binary location |
Platform-specific |
3.3 Profile Validation
The system SHOULD validate profiles against the MREP JSON Schema before use. Invalid profiles MUST be logged and MUST NOT prevent operation, but the invalid sections MUST be ignored.
4. Shell Profile Integration
4.1 Linux and Unix-like Systems
The installation MUST provide a shell profile script at:
- System-wide:
/etc/profile.d/metacall.sh
- User-installable:
$METACALL_HOME/etc/metacall.sh
The profile script MUST:
- Determine the installation prefix
- Source the runtime environment profile
- Export all necessary environment variables
- Provide a
metacall_env helper function for debugging
Example /etc/profile.d/metacall.sh:
# MetaCall Runtime Environment Profile
# Generated by MetaCall installation
METACALL_PREFIX="/usr/local"
METACALL_HOME="${METACALL_HOME:-${HOME}/.metacall}"
if [ -f "${METACALL_PREFIX}/etc/metacall/environment.json" ]; then
# Source generated environment from profile
. "${METACALL_PREFIX}/etc/metacall/metacall-env.sh"
elif [ -f "${METACALL_HOME}/environment.json" ]; then
. "${METACALL_HOME}/etc/metacall-env.sh"
fi
# Helper function to display current MetaCall environment
metacall_env() {
echo "MetaCall Environment:"
echo " METACALL_PREFIX: ${METACALL_PREFIX}"
echo " METACALL_HOME: ${METACALL_HOME}"
echo " LOADER_LIBRARY_PATH: ${LOADER_LIBRARY_PATH}"
echo " LOADER_SCRIPT_PATH: ${LOADER_SCRIPT_PATH}"
}
4.2 Windows
On Windows, the installation SHOULD:
- Create a PowerShell profile snippet at
$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
- Or provide a batch file at
%USERPROFILE%\metacall_env.bat for cmd.exe users
- Register
METACALL_ENVIRONMENT in the user environment variables
4.3 macOS
On macOS with Homebrew, the formula MUST:
- Provide a bash/zshrc snippet via
etc/profile.d/metacall.sh
- Respect
HOMEBREW_PREFIX as the installation prefix
- Follow Homebrew conventions for profile.d integration
5. C API Extensions
5.1 New Functions
The following functions SHOULD be added to metacall.h:
/**
* Initialize the runtime environment from the active profile.
* This function reads the MREP, resolves paths, and sets
* necessary environment variables before loader initialization.
*
* Returns 0 on success, non-zero on failure.
*/
int metacall_initialize_environment(void);
/**
* Get the runtime configuration for a specific language.
* The returned pointer MUST NOT be freed by the caller.
*
* Returns NULL if the language is not configured.
*/
const metacall_runtime_config_t metacall_get_runtime_config(const char *language);
/**
* Iterate over all configured runtimes.
* The callback is invoked for each runtime with its name and config.
* Return non-zero from callback to stop iteration.
*/
int metacall_foreach_runtime(
int (*callback)(const char *language, const metacall_runtime_config_t config, void *user),
void *user
);
5.2 Runtime Configuration Structure
typedef struct metacall_runtime_config_type {
const char *language; // Language identifier (e.g., "python", "ruby")
const char *home; // Resolved runtime home path
const char **search_paths; // Array of search paths (NULL-terminated)
const char **environment; // Array of "KEY=VALUE" strings (NULL-terminated)
} * metacall_runtime_config_t;
6. Loader Integration
6.1 Profile-Driven Initialization
Loaders SHOULD use the MREP system for runtime initialization instead of implementing platform-specific logic. The loader initialization flow becomes:
1. metacall_initialize_environment() reads and parses MREP
2. For each runtime in profile:
a. Resolve variable references
b. Set environment variables from profile
c. Store resolved paths for loader use
3. Loader initialization reads resolved paths from profile
4. Platform-specific env var code is replaced by profile lookup
6.2 Fallback Behavior
The system MUST maintain backward compatibility:
- If no profile is found, fall back to existing environment variable behavior
- If a specific runtime is not in the profile, use loader-specific defaults
- Log a warning when falling back to deprecated behavior
7. Port Integration
7.1 MetaCall-sys (Rust)
The Rust port build script MUST generate METACALL_RUNTIME_CONFIG from the installed profile:
// In build.rs
fn main() {
// Read installed profile if present
if let Some(profile) = find_metacall_profile() {
// Emit runtime config to generated code
println!("cargo:rustc-env=METACALL_RUNTIME_CONFIG={}", profile);
}
}
The ensure_python_home() function in rs_port SHOULD be replaced with:
fn ensure_runtime_env() {
// Call metacall_initialize_environment() from C API
// This handles all languages, not just Python
}
7.2 Other Ports
All ports (Go, Java, C#, etc.) SHOULD follow the same pattern:
- Load the C library with
metacall_initialize_environment() call
- Or read
METACALL_RUNTIME_CONFIG environment variable if set
- Do not implement per-language fallback logic
8. Profile Generation
8.1 CMake Integration
The CMake installation process SHOULD generate environment.json during installation:
# In loaders/CMakeLists.txt
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/environment.json.in"
"${CMAKE_CURRENT_BINARY_DIR}/environment.json"
@ONLY
)
The template file MUST use CMake variables for path substitution:
{
"meta": {
"version": "1.0.0",
"generated": "@METACALL_GENERATED_TIMESTAMP@"
},
"runtimes": {
"python": {
"home": "@PYTHON_HOME@",
"search_paths": [@LOADER_SEARCH_PATHS@]
}
},
"defaults": {
"loaders_path": "@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB@/metacall/loaders"
}
}
8.2 Shell Script Generation
During installation, a shell script MUST be generated from the profile:
#!/bin/bash
# Generated from MetaCall environment.json
export METACALL_PREFIX="@CMAKE_INSTALL_PREFIX@"
export LOADER_LIBRARY_PATH="@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB@/metacall/loaders"
export LOADER_SCRIPT_PATH="@CMAKE_INSTALL_PREFIX@/@INSTALL_DATA@/metacall/scripts"
export CONFIGURATION_PATH="@CMAKE_INSTALL_PREFIX@/@INSTALL_DATA@/metacall/config/global.json"
# Python runtime environment
if [ -z "$PYTHONHOME" ]; then
export PYTHONHOME="@PYTHON_HOME@"
fi
9. Backward Compatibility
9.1 Environment Variables
Existing environment variables MUST continue to work:
| Variable |
Behavior |
Deprecated |
LOADER_LIBRARY_PATH |
Still honored, profile takes precedence |
No |
LOADER_SCRIPT_PATH |
Still honored, profile takes precedence |
No |
PYTHONHOME |
Still honored, profile takes precedence |
Yes |
METACALL_CONFIG |
Still honored, profile takes precedence |
No |
9.2 Configuration Files
Existing loader.json files MUST continue to be loaded. The MREP system provides additional configuration that supplements but does not replace existing mechanisms.
Requirements
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Implementation Requirements
Implementations of this RFC:
- MUST provide a mechanism for profile discovery as specified in Section 3.1
- MUST resolve variable references according to the rules in Section 3.2
- MUST maintain backward compatibility with existing environment variables
- MUST provide shell profile integration for Linux, Windows, and macOS
- MUST generate shell scripts from profiles during installation
- MUST NOT break existing installations that do not use profiles
Design Recommendations
Implementations:
- SHOULD validate profiles against the MREP JSON Schema
- SHOULD log warnings when falling back to deprecated behavior
- SHOULD provide tooling for profile generation and validation
- SHOULD document the profile format in user-facing documentation
- MAY provide additional variable reference formats beyond those specified
- MAY extend the MREP schema with loader-specific fields
References
Standards
- RFC 2119 - Key words for use in RFCs to Indicate Requirement Levels
- ISO 8601 - Date and time format
- JSON Schema - JSON Schema specification
Related Systems
- SDKMAN - Software Development Kit Manager
- Conda Environment Files - Conda environment specification
- GraalVM Native - GraalVM metadata approach
- asdf Version Manager - Multi-language version manager
MetaCall Resources
- MetaCall GitHub Repository - Main codebase
- PR #734 - Windows Python initialization fix
- MetaCall Configuration - Current configuration system
- PR #738
Appendix A: Migration Guide "which all of them are one person"
For Loader Developers
To migrate an existing loader to use MREP:
- Remove platform-specific environment variable code
- Replace with calls to
metacall_get_runtime_config()
- Use resolved paths from the configuration structure
- Remove
#if defined(WIN32) blocks for environment setup
For Port Developers
To update a port to use MREP:
- Remove per-language fallback functions (e.g.,
ensure_python_home())
- Call
metacall_initialize_environment() early in initialization
- Or read
METACALL_RUNTIME_CONFIG from environment
For Package Maintainers
To integrate MREP into distribution packages:
- Ensure
environment.json is generated at build time
- Install shell profile script to
/etc/profile.d/
- Set
METACALL_PREFIX to installation prefix
- Document the profile requirement in package metadata
Appendix B: Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://metacall.io/schemas/mrep-v1.json",
"title": "MetaCall Runtime Environment Profile",
"description": "Declarative configuration for MetaCall runtime environments",
"type": "object",
"required": ["meta", "runtimes"],
"properties": {
"meta": {
"type": "object",
"required": ["version", "schema"],
"properties": {
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"schema": {
"type": "string",
"format": "uri"
},
"generated": {
"type": "string",
"format": "date-time"
}
}
},
"runtimes": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"home": { "type": "string" },
"search_paths": {
"type": "array",
"items": { "type": "string" }
},
"environment": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"options": {
"type": "object",
"additionalProperties": true
}
}
}
},
"defaults": {
"type": "object",
"properties": {
"loaders_path": { "type": "string" },
"scripts_path": { "type": "string" },
"config_path": { "type": "string" }
}
}
}
}
Status
RFC 0001
Drafted "v0.0.2"
Related PRs:
#734
Abstract
This RFC proposes a standardized mechanism for defining and propagating runtime environment configuration across MetaCall loaders and ports. The mechanism introduces a declarative environment profile format that centralizes runtime home paths, search paths, and initialization requirements, replacing the current pattern of duplicative platform-specific code in each loader and port implementation.
Motivation
The Problem
The current MetaCall architecture requires each loader and port to implement its own platform-specific initialization logic. Consider the changes introduced in PR #734 to fix Windows Python initialization and mainly it's a repeated problem in CIs and Infrastructure:
py_loader_impl_initialize_python_home()to setPYTHONHOMEbeforePy_InitializeEx()ensure_python_home()as a fallback for backward compatibilityThis pattern creates several issues:
#if defined(WIN32)blocks scattered across the codebaseThe Opportunity
Other polyglot runtimes and version managers have solved similar problems through declarative profile systems:
~/.sdkman/etc/configand~/.sdkman/candidates/layoutenvironment.ymlwith explicit channel and dependency declarationsMETA-INF/native-image/with structured metadata.tool-versionsfor project-level runtime specificationMetaCall already has a configuration system (
loader.json.in,global.json). The opportunity is to extend this with a dedicated runtime environment profile that:Delimma
A developer installs MetaCall on a fresh Linux system. They want to run Python and Node scripts that call each other. With the current system, they must:
LOADER_LIBRARY_PATHSERIAL_LIBRARY_PATHPYTHONHOMEandNODE_PATHWith the proposed system, they run:
source /etc/profile.d/metacall.shAnd the profile script automatically sets all necessary variables based on the installed runtime configuration.
Specification
1. Terminology
2. Profile Format
The MREP format uses JSON with the following schema:
{ "$schema": "https://metacall.io/schemas/mrep-v1.json", "meta": { "version": "1.0.0", "schema": "https://metacall.io/schemas/mrep-v1.json", "generated": "2024-01-15T10:30:00Z" }, "runtimes": { "<language>": { "home": "<absolute-path-or-variable-reference>", "search_paths": ["<path>", "<path>"], "environment": { "<VAR_NAME>": "<value>" }, "options": { "<option>": "<value>" } } }, "defaults": { "loaders_path": "<path>", "scripts_path": "<path>", "config_path": "<path>" } }2.1 Field Definitions
meta.versionmeta.schemameta.generatedruntimes.<language>.homeruntimes.<language>.search_pathsruntimes.<language>.environmentruntimes.<language>.optionsdefaults.loaders_pathdefaults.scripts_pathdefaults.config_path2.2 Variable References
The
homefield supports variable references for flexible path resolution:$METACALL_PREFIX/usr/local$METACALL_HOME/etc/metacall$ORIGIN<os-family>%LOCALAPPDATA%\MetaCall2.3 Example Profiles
Linux System Installation:
{ "meta": { "version": "1.0.0", "schema": "https://metacall.io/schemas/mrep-v1.json", "generated": "2024-01-15T10:30:00Z" }, "runtimes": { "python": { "home": "$METACALL_PREFIX/lib/metacall/runtimes/python", "search_paths": [ "$METACALL_PREFIX/lib", "$METACALL_PREFIX/lib/metacall/runtimes/python/lib" ], "environment": { "PYTHONIOENCODING": "utf-8", "PYTHONDONTWRITEBYTECODE": "1" } }, "ruby": { "home": "$METACALL_PREFIX/lib/metacall/runtimes/ruby", "search_paths": [ "$METACALL_PREFIX/lib", "$METACALL_PREFIX/lib/metacall/runtimes/ruby/lib" ] }, "node": { "home": "$METACALL_PREFIX/lib/metacall/runtimes/node", "search_paths": [ "$METACALL_PREFIX/lib" ] } }, "defaults": { "loaders_path": "$METACALL_PREFIX/lib/metacall/loaders", "scripts_path": "$METACALL_PREFIX/share/metacall/scripts", "config_path": "$METACALL_PREFIX/etc/metacall/global.json" } }Windows Installation:
{ "meta": { "version": "1.0.0", "schema": "https://metacall.io/schemas/mrep-v1.json", "generated": "2024-01-15T10:30:00Z" }, "runtimes": { "python": { "home": "%LOCALAPPDATA%\\MetaCall\\runtimes\\python", "search_paths": [ "%LOCALAPPDATA%\\MetaCall\\lib", "%LOCALAPPDATA%\\MetaCall\\runtimes\\python" ], "environment": { "PYTHONHOME": "%LOCALAPPDATA%\\MetaCall\\runtimes\\python", "PYTHONIOENCODING": "utf-8" } } }, "defaults": { "loaders_path": "%LOCALAPPDATA%\\MetaCall\\loaders", "scripts_path": "%LOCALAPPDATA%\\MetaCall\\scripts", "config_path": "%LOCALAPPDATA%\\MetaCall\\config\\global.json" } }2.4 Python Path Matrix
The table below captures the current Python-related paths used by MetaCall as requested.
PYTHONPATH/gnu/lib/libmetacall(.so)(also searched by Python/Node/Ruby ports via/gnu/lib)/gnu/store/..., exposed through/gnuprofilePYTHONPATH=/gnu/lib/python<major.minor>/site-packages(from/gnu/etc/profile); installer wrapper also appendslib-dynloadCONFIGURATION_PATH=/gnu/configurations/global.jsonLOADER_LIBRARY_PATH=/gnu/lib,SERIAL_LIBRARY_PATH=/gnu/lib,DETOUR_LIBRARY_PATH=/gnu/lib,PORT_LIBRARY_PATH=/gnu/libmetacall/homebrew)/opt/homebrew/lib/libmetacall(.dylib)(arm64) or/usr/local/lib/libmetacall(.dylib)(intel)python@3.x) viapython.opt_*(no fixedPYTHONHOME)PYTHONPATH=${PREFIX}/lib/python:${PYTHONPATH:-}; formula tests also use${HOMEBREW_PREFIX}/lib/pythonCONFIGURATION_PATH=${PREFIX}/configurations/global.jsonSERIAL_LIBRARY_PATH,DETOUR_LIBRARY_PATH,PORT_LIBRARY_PATHto${PREFIX}/lib(note: current formula usesLOADER_LIBRARY, notLOADER_LIBRARY_PATH)apt/dpkg)/usr/local/lib/libmetacall(.so)PYTHONPATHexport by default; relies on system Python layout/usr/local/share/metacall/configurations/global.json(or configured prefix equivalent)<prefix>/libinstall.ps1+ zip asset)%LOCALAPPDATA%\MetaCall\metacalland recursively findsmetacall(.dll)(currently stored under...\lib)%LOCALAPPDATA%\MetaCall\metacall\runtimes\python(PYTHONHOME)PIP_TARGET=%LOCALAPPDATA%\MetaCall\metacall\runtimes\python\Lib\site-packages; runtimePATHincludes Python/Scripts/site-packages binCONFIGURATION_PATH=%LOCALAPPDATA%\MetaCall\metacall\configurations\global.jsonLOADER_LIBRARY_PATH,SERIAL_LIBRARY_PATH,DETOUR_LIBRARY_PATH,PORT_LIBRARY_PATHall exported to%LOCALAPPDATA%\MetaCall\metacall\libWindows installer note: current core packaging generators are
NSIS;ZIP(not MSI). The Windows one-line installer consumesmetacall-tarball-win-<arch>.zipassets frommetacall/distributable-windows.Implication for MREP abstraction: Python path resolution needs at least three explicit layers:
METACALL_INSTALL_PATH,PYTHONHOME, etc.)This preserves compatibility with existing installs while removing per-port/per-loader hardcoded path duplication.
3. Profile Discovery
3.1 Discovery Order
The system MUST search for profiles in the following order, with earlier entries taking precedence:
$METACALL_ENVIRONMENT- Explicit profile path via environment variable$METACALL_HOME/environment.json- User-level profile$METACALL_PREFIX/etc/metacall/environment.json- System installation profile3.2 Path Resolution
Variable references in profiles MUST be resolved according to the following rules:
$METACALL_PREFIXCMAKE_INSTALL_PREFIXor equivalent/usr/local$METACALL_HOME$HOME/.metacall~/.metacall$ORIGIN3.3 Profile Validation
The system SHOULD validate profiles against the MREP JSON Schema before use. Invalid profiles MUST be logged and MUST NOT prevent operation, but the invalid sections MUST be ignored.
4. Shell Profile Integration
4.1 Linux and Unix-like Systems
The installation MUST provide a shell profile script at:
/etc/profile.d/metacall.sh$METACALL_HOME/etc/metacall.shThe profile script MUST:
metacall_envhelper function for debuggingExample
/etc/profile.d/metacall.sh:4.2 Windows
On Windows, the installation SHOULD:
$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1%USERPROFILE%\metacall_env.batfor cmd.exe usersMETACALL_ENVIRONMENTin the user environment variables4.3 macOS
On macOS with Homebrew, the formula MUST:
etc/profile.d/metacall.shHOMEBREW_PREFIXas the installation prefix5. C API Extensions
5.1 New Functions
The following functions SHOULD be added to
metacall.h:5.2 Runtime Configuration Structure
6. Loader Integration
6.1 Profile-Driven Initialization
Loaders SHOULD use the MREP system for runtime initialization instead of implementing platform-specific logic. The loader initialization flow becomes:
6.2 Fallback Behavior
The system MUST maintain backward compatibility:
7. Port Integration
7.1 MetaCall-sys (Rust)
The Rust port build script MUST generate
METACALL_RUNTIME_CONFIGfrom the installed profile:The
ensure_python_home()function inrs_portSHOULD be replaced with:7.2 Other Ports
All ports (Go, Java, C#, etc.) SHOULD follow the same pattern:
metacall_initialize_environment()callMETACALL_RUNTIME_CONFIGenvironment variable if set8. Profile Generation
8.1 CMake Integration
The CMake installation process SHOULD generate
environment.jsonduring installation:The template file MUST use CMake variables for path substitution:
{ "meta": { "version": "1.0.0", "generated": "@METACALL_GENERATED_TIMESTAMP@" }, "runtimes": { "python": { "home": "@PYTHON_HOME@", "search_paths": [@LOADER_SEARCH_PATHS@] } }, "defaults": { "loaders_path": "@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB@/metacall/loaders" } }8.2 Shell Script Generation
During installation, a shell script MUST be generated from the profile:
9. Backward Compatibility
9.1 Environment Variables
Existing environment variables MUST continue to work:
LOADER_LIBRARY_PATHLOADER_SCRIPT_PATHPYTHONHOMEMETACALL_CONFIG9.2 Configuration Files
Existing
loader.jsonfiles MUST continue to be loaded. The MREP system provides additional configuration that supplements but does not replace existing mechanisms.Requirements
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Implementation Requirements
Implementations of this RFC:
Design Recommendations
Implementations:
References
Standards
Related Systems
MetaCall Resources
Appendix A: Migration Guide "which all of them are one person"
For Loader Developers
To migrate an existing loader to use MREP:
metacall_get_runtime_config()#if defined(WIN32)blocks for environment setupFor Port Developers
To update a port to use MREP:
ensure_python_home())metacall_initialize_environment()early in initializationMETACALL_RUNTIME_CONFIGfrom environmentFor Package Maintainers
To integrate MREP into distribution packages:
environment.jsonis generated at build time/etc/profile.d/METACALL_PREFIXto installation prefixAppendix B: Schema
{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://metacall.io/schemas/mrep-v1.json", "title": "MetaCall Runtime Environment Profile", "description": "Declarative configuration for MetaCall runtime environments", "type": "object", "required": ["meta", "runtimes"], "properties": { "meta": { "type": "object", "required": ["version", "schema"], "properties": { "version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" }, "schema": { "type": "string", "format": "uri" }, "generated": { "type": "string", "format": "date-time" } } }, "runtimes": { "type": "object", "additionalProperties": { "type": "object", "properties": { "home": { "type": "string" }, "search_paths": { "type": "array", "items": { "type": "string" } }, "environment": { "type": "object", "additionalProperties": { "type": "string" } }, "options": { "type": "object", "additionalProperties": true } } } }, "defaults": { "type": "object", "properties": { "loaders_path": { "type": "string" }, "scripts_path": { "type": "string" }, "config_path": { "type": "string" } } } } }