Part 7 · Advanced & Integration · Intermediate
`include & Guard Discipline
Textual include semantics, the double-include failure, ifndef guard pattern, +incdir+ search paths, and include-based class libraries.
`include is textual paste
`include "file.svh" replaces the directive with the entire contents of the file , verbatim, at that exact spot — as if you had typed it there. It is not an import, not a module reference, and creates no namespace. The included text is then preprocessed and compiled in whatever context surrounds the include — inside a package, inside a module, or at file scope.
// my_pkg.sv — the canonical include-based class library layout
package my_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
// Order matters: base classes before derived classes,
// because this is literal text pasted top to bottom.
`include "my_txn.svh" // class my_txn extends uvm_sequence_item
`include "my_driver.svh" // uses my_txn — must come after it
`include "my_monitor.svh"
`include "my_agent.svh" // uses driver + monitor
endpackage
// Compile the PACKAGE file; the .svh files are never compiled
// on their own — they only exist as text pasted into the package.The double-include failure and the guard
If two files both include the same header, the class inside it gets pasted — and therefore declared — twice, producing a duplicate-definition compile error. The fix is the ifndef include guard : the first paste defines a marker macro; every later paste sees the marker already defined and skips the body.
// my_txn.svh — guarded header, safe to include any number of times
`ifndef MY_TXN_SVH // first include: not yet defined → enter
`define MY_TXN_SVH // define the marker immediately
class my_txn extends uvm_sequence_item;
rand bit [31:0] addr;
rand bit [31:0] data;
`uvm_object_utils_begin(my_txn)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_txn");
super.new(name);
endfunction
endclass
`endif // MY_TXN_SVH // comment the endif — helps when guards nestDOUBLE-INCLUDE: FAILURE vs GUARD
WITHOUT GUARD WITH GUARD
───────────── ──────────
driver.svh: `include "my_txn.svh" driver.svh: `include "my_txn.svh"
monitor.svh: `include "my_txn.svh" monitor.svh: `include "my_txn.svh"
│ │
▼ both pasted into package ▼
class my_txn ... ← 1st copy 1st paste: MY_TXN_SVH undefined
class my_txn ... ← 2nd copy → define it, paste class body
│ 2nd paste: MY_TXN_SVH defined
▼ → body skipped entirely
ERROR: 'my_txn' already declared COMPILES CLEANInclude paths and library organization
The preprocessor finds included files by searching directories given with +incdir+ (plus the including file's own directory, tool-dependent). Source code stays portable — it names only the file, and the build flow supplies the search path.
# Each agent directory added to the include search path
vcs +incdir+tb/agents/bus_agent \
+incdir+tb/agents/mem_agent \
+incdir+tb/env \
tb/my_pkg.sv tb/tb_top.sv
# Source says: `include "bus_driver.svh"
# Preprocessor searches: tb/agents/bus_agent/ → foundLibrary conventions that scale
.sv files are compilation units (packages, modules); .svh files are include-only fragments that never compile standalone.
Every .svh file gets a guard whose macro name mirrors the file path — MY_PROJ_BUS_DRIVER_SVH — to avoid collisions between same-named files in different agents.
One package file per agent or env includes its .svh files in dependency order; everything else imports the package.
Never `include a file that declares a module — modules belong in separately compiled .sv files; includes are for classes, macros, and shared declarations.
Key takeaways
`include is literal text paste — included files compile in the surrounding context, and paste order is dependency order.
Guard every .svh header with `ifndef/`define/`endif so multiple includes are harmless.
Use +incdir+ for search paths; keep file names (not paths) in source for portability.
Organize class libraries as one compiled package that includes guarded .svh fragments in dependency order.
Common pitfalls
Guard macro name copy-pasted between two headers — the second include silently vanishes because the marker is already defined.
Compiling a .svh file directly — classes land in the file's compilation scope instead of the intended package, causing baffling type-mismatch errors.
Includes in the wrong order inside a package — derived class pasted before its base class fails to compile.
Missing +incdir+ for a nested directory — 'cannot find include file' even though the file plainly exists on disk.
Interview angle
Common questions: what `include actually does (text paste, not import); why a class declared twice errors and how guards prevent it; difference between `include and package import (text insertion vs compiled-symbol visibility). A favorite trap: two headers accidentally sharing one guard macro name — explain why one class silently disappears.