Environment & Paths

Overview

IVPM provides two mechanisms for managing project-specific configuration:

  1. Environment Variables - Set, modify, and export shell variables

  2. Project Paths - Organize and export file paths by category

Both features help tools discover project resources and configuration.

Environment Variables

Note

IVPM delegates environment application to direnv. It does not set variables in your shell itself; instead it emits the env: directives (together with each package’s export.envrc) into packages/packages.envrc. Running direnv allow once authorizes that file, after which the environment loads automatically whenever you are in the project directory.

Declaring Environment Variables

Define environment variables in ivpm.yaml with a top-level env: list. Each entry names a variable and one action (see below):

package:
  name: my-project

  env:
    - name: MY_VAR
      value: "hello world"
    - name: PROJECT_ROOT
      value: "${IVPM_PROJECT}"

When env: directives (or packages that publish export.envrc) are present, ivpm update writes packages/packages.envrc. env: directives are emitted last, so the project’s own declarations take precedence over variables set by packages.

Built-in Variables:

The direnv handler always writes these into packages.envrc:

  • IVPM_PROJECT - Path to project root directory

  • IVPM_PACKAGES - Path to packages directory

They are available to your own env: directives via ${IVPM_PROJECT} / ${IVPM_PACKAGES} (expanded by direnv at load time).

Variable Actions

IVPM supports four actions, each mapping to a direnv/bash directive:

value

Set a variable to a literal value:

env:
  - name: BUILD_TYPE
    value: "debug"

  - name: MAX_JOBS
    value: "4"

Result:

export BUILD_TYPE="debug"
export MAX_JOBS="4"

With lists (space-separated):

env:
  - name: CFLAGS
    value:
      - "-O2"
      - "-Wall"
      - "-Werror"

Result:

export CFLAGS="-O2 -Wall -Werror"

path

Set a variable as a path (colon-separated):

env:
  - name: LD_LIBRARY_PATH
    path:
      - "${IVPM_PACKAGES}/lib1/lib"
      - "${IVPM_PACKAGES}/lib2/lib"
      - "/usr/local/lib"

Result:

export LD_LIBRARY_PATH="${IVPM_PACKAGES}/lib1/lib:${IVPM_PACKAGES}/lib2/lib:/usr/local/lib"

path-append

Append to an existing path variable:

env:
  - name: PATH
    path-append:
      - "${IVPM_PACKAGES}/bin"
      - "${IVPM_PACKAGES}/tools/bin"

Result (emitted into packages.envrc):

# A leading ':' separator is added only when PATH is already set
export PATH="${PATH:+$PATH:}${IVPM_PACKAGES}/bin:${IVPM_PACKAGES}/tools/bin"

path-prepend

Prepend to an existing path variable:

env:
  - name: PYTHONPATH
    path-prepend:
      - "${IVPM_PROJECT}/src"
      - "${IVPM_PACKAGES}/mylib/src"

Result (uses the direnv stdlib path_add, which prepends its arguments and de-duplicates on re-source):

path_add PYTHONPATH "${IVPM_PROJECT}/src" "${IVPM_PACKAGES}/mylib/src"

Variable Expansion

${VAR} references are emitted verbatim and expanded by direnv (via bash) when the environment loads – IVPM does not expand them itself:

env:
  # Use built-in IVPM variables
  - name: PROJECT_SRC
    value: "${IVPM_PROJECT}/src"

  # Reference previously-set variables
  - name: LIB_PATH
    value: "${PROJECT_SRC}/lib"

  # Reference system environment
  - name: USER_HOME
    value: "${HOME}"

Order matters: Variables are processed in order, so you can reference earlier variables in later ones.

Complete Environment Example

package:
  name: verification-project

  env:
    # Set project paths
    - name: PROJECT_ROOT
      value: "${IVPM_PROJECT}"

    - name: RTL_ROOT
      value: "${PROJECT_ROOT}/rtl"

    - name: TB_ROOT
      value: "${PROJECT_ROOT}/testbench"

    # Configure build
    - name: BUILD_TYPE
      value: "release"

    - name: CFLAGS
      value:
        - "-O2"
        - "-Wall"

    # Add tools to PATH
    - name: PATH
      path-prepend:
        - "${IVPM_PACKAGES}/tools/bin"
        - "${PROJECT_ROOT}/scripts"

    # Set library paths
    - name: LD_LIBRARY_PATH
      path:
        - "${IVPM_PACKAGES}/lib64"
        - "${IVPM_PACKAGES}/lib"

    # Configure Python
    - name: PYTHONPATH
      path-prepend: "${IVPM_PROJECT}/src"

Loading the Environment

The generated packages.envrc is consumed by direnv. Authorize it once with direnv allow; thereafter the environment loads automatically whenever you cd into the project:

$ direnv allow
$ echo $PROJECT_ROOT
/home/user/projects/myproject

$ echo $PATH
/home/user/projects/myproject/packages/tools/bin:/home/user/projects/myproject/scripts:...

To run a single command in the project environment without an interactive shell, use direnv exec:

$ direnv exec . pytest

Note

Windows: direnv evaluates packages.envrc with bash, so a bash is required even under PowerShell. The supported setup is direnv + git-bash (bundled with Git-for-Windows). For native PowerShell, add Invoke-Expression "$(direnv hook pwsh)" to your $PROFILE; inside git-bash or WSL use direnv normally.

Or for a single command:

$ direnv exec . echo \$PROJECT_ROOT
/home/user/projects/myproject

Project Paths

The paths section organizes project file paths by category for tools to discover.

Path Organization

Paths are organized by:

  1. Kind - High-level category (e.g., rtl, dv, docs)

  2. Type - Specific type within kind (e.g., vlog, sv, vhdl)

Basic Structure

Software project:

package:
  name: web-service

  paths:
    src:
      python:
        - src/api
        - src/workers
      typescript:
        - frontend/src
    test:
      python:
        - test/unit
        - test/integration
    config:
      yaml:
        - deploy/k8s
        - deploy/terraform

Hardware project:

package:
  name: soc-design

  paths:
    rtl:                    # Kind: RTL source
      vlog:                 # Type: Verilog
        - rtl/common
        - rtl/peripherals
      sv:                   # Type: SystemVerilog
        - rtl/cpu
        - rtl/bus

    dv:                     # Kind: Design verification
      sv:                   # Type: SystemVerilog
        - tb/agents
        - tb/sequences
      python:               # Type: Python
        - tb/models

Paths are relative to the project root (directory containing ivpm.yaml).

Common Path Categories

rtl - RTL source files:

  • vlog - Verilog files

  • sv - SystemVerilog files

  • vhdl - VHDL files

dv - Design verification:

  • sv - SystemVerilog testbench

  • python - Python testbench

  • c - C/C++ models

docs - Documentation:

  • rst - ReStructuredText

  • md - Markdown

  • pdf - PDF files

data - Data files:

  • testdata - Test vectors

  • config - Configuration files

src - Source code:

  • python - Python source files

  • typescript - TypeScript source files

  • go - Go source files

test - Test suites:

  • python - Python tests

  • typescript - TypeScript tests

  • shell - Shell-based integration tests

config - Configuration and deployment:

  • yaml - YAML configuration files

  • json - JSON configuration files

  • toml - TOML configuration files

Complete Paths Example

package:
  name: uart-ip

  paths:
    # RTL source files
    rtl:
      sv:
        - rtl/uart_core
        - rtl/uart_tx
        - rtl/uart_rx
      vlog:
        - rtl/uart_apb_if

    # Verification
    dv:
      sv:
        - tb/uart_agent
        - tb/uart_monitor
        - tb/sequences
      python:
        - tb/models
        - tb/tests

    # Documentation
    docs:
      rst:
        - docs/source
      md:
        - docs/guides

    # IP-XACT or other metadata
    metadata:
      ipxact:
        - ip-xact/uart.xml

    # Scripts
    scripts:
      python:
        - scripts/build
      shell:
        - scripts/sim

Using Path Information

Tools can query path information via the ivpm pkg-info command:

# Get all RTL SystemVerilog paths
$ ivpm pkg-info paths -k rtl --type sv my-package

# Get all verification paths
$ ivpm pkg-info paths -k dv my-package

This enables tools like FuseSoC, simulators, and build systems to discover source files automatically.

Practical Examples

Example 1: Simulation Environment

package:
  name: cpu-verification

  env:
    # Simulation variables
    - name: SIM_ROOT
      value: "${IVPM_PROJECT}"

    - name: WORK_DIR
      value: "${SIM_ROOT}/work"

    - name: LOG_DIR
      value: "${SIM_ROOT}/logs"

    # Simulator paths
    - name: PATH
      path-prepend:
        - "${IVPM_PACKAGES}/verilator/bin"
        - "${IVPM_PACKAGES}/gtkwave/bin"

    # Library paths for compiled libraries
    - name: LD_LIBRARY_PATH
      path:
        - "${IVPM_PACKAGES}/lib"
        - "${SIM_ROOT}/build/lib"

  paths:
    rtl:
      sv:
        - rtl/core
        - rtl/cache
        - rtl/mmu
    dv:
      sv:
        - tb/top
        - tb/agents
      python:
        - tb/tests

Usage:

$ ivpm update
$ direnv allow
$ cd $WORK_DIR
$ make sim

Example 2: Multi-Language Project

package:
  name: mixed-project

  env:
    # Project structure
    - name: HDL_ROOT
      value: "${IVPM_PROJECT}/hdl"

    - name: SW_ROOT
      value: "${IVPM_PROJECT}/software"

    # Compilation flags
    - name: VLOG_FLAGS
      value:
        - "+incdir+${HDL_ROOT}/include"
        - "-timescale=1ns/1ps"

    - name: CFLAGS
      value:
        - "-I${SW_ROOT}/include"
        - "-Wall"

    # Tool configuration
    - name: PYTHONPATH
      path-prepend:
        - "${SW_ROOT}/python"
        - "${IVPM_PROJECT}/scripts"

  paths:
    rtl:
      vlog:
        - hdl/rtl
      sv:
        - hdl/interfaces

    sw:
      c:
        - software/drivers
        - software/firmware
      python:
        - software/python

Example 3: Team Development Setup

package:
  name: team-project

  env:
    # Project info
    - name: PROJECT_NAME
      value: "TeamProject"

    - name: PROJECT_VERSION
      value: "1.0.0"

    # Shared tools (from packages/)
    - name: TOOL_ROOT
      value: "${IVPM_PACKAGES}/tools"

    - name: PATH
      path-prepend:
        - "${TOOL_ROOT}/bin"
        - "${IVPM_PROJECT}/scripts"

    # License servers
    - name: LM_LICENSE_FILE
      path:
        - "27000@license-server-1"
        - "27001@license-server-2"

    # Output directories
    - name: BUILD_DIR
      value: "${IVPM_PROJECT}/build"

    - name: REPORT_DIR
      value: "${IVPM_PROJECT}/reports"

Best Practices

  1. Use built-in variables (IVPM_PROJECT, IVPM_PACKAGES) for portability

  2. Define variables in order - reference order matters for expansion

  3. Use path-prepend for tools - Ensure project tools override system tools

  4. Document custom variables - Help team members understand the setup

  5. Keep paths relative - Use ${IVPM_PROJECT} for portability

  6. Group related variables - Organize by purpose (build, test, docs)

  7. Test after changes - Always verify with direnv exec . env

See Also