This is a sample project of an svlint
plugin.
An svlint plugin implements one or more rules (either TextRule or
SyntaxRule) in an externally developed project, compiling a shared object
file which is dynamically loaded at svlint runtime.
Use svlint's --plugin option with the shared object produced by cargo build
in this repository.
The shared object can be copied from target/(debug|release)/, but the
filename will be platform-dependent.
- Linux:
lib<name>.so - MacOS:
lib<name>.dylib - Windows:
<name>.dll
$ svlint --plugin libsvlint_plugin_sample.so test.sv
Fail: sample_plugin
--> test.sv:2:1
|
2 | initial begin
| ^^^^^^^ hint : Remove the `initial` process.
| reason: This example doesn't like `initial` processes.
The loaded plugin is automatically enabled, has access to values from svlint's TOML configuration, and syntax rules may be controlled using special comments.
As a plugin must create a shared object, the crate type of Cargo.toml should
be cdylib.
Alternatively, dylib could be used, but the resulting binary may be very
large.
[lib]
crate-type = ["cdylib"]A plugin project must define a
get_plugin
function (in src/lib.rs) which returns the list of rules that it implements.
Svlint provides a macro pluginrules
which makes this quite simple.
#[allow(improper_ctypes_definitions)]
#[no_mangle]
pub extern "C" fn get_plugin() -> Vec<Rule> {
pluginrules!(
SamplePlugin,
AnotherPlugin,
ForbiddenRegex
)
}Rules are defined by the TextRule or SyntaxRule traits, see
src/forbidden_regex.rs
and
src/another_plugin.rs
for examples of each.
impl SyntaxRule for SamplePlugin {
fn check(
&mut self,
_syntax_tree: &Tree,
event: &NodeEvent,
_config: &ConfigOption,
) -> SyntaxRuleResult {
match event {
NodeEvent::Enter(RefNode::InitialConstruct(_)) => SyntaxRuleResult::Fail,
_ => SyntaxRuleResult::Pass,
}
}
fn name(&self) -> String {
String::from("sample_plugin")
}
fn hint(&self, _config: &ConfigOption) -> String {
String::from("Remove the `initial` process.")
}
fn reason(&self) -> String {
String::from("This example doesn't like `initial` processes.")
}
}TextRule must implement check, name, hint and reason.
SyntaxRule must implement check, name, hint and reason.
This sample project includes a basic test infrastructure to test its rules.
To run the tests, first build the shared object (cargo build), then run
cargo test.
If you wish to debug via println, run cargo test -- --show-output.
The test infrastructure has 3 main parts:
- The
testsmodule insrc/lib.rs.
so_path(): Return a string with the expected filesystem path of the shared object. If your plugin has an unusual name (specified inCargo.toml), then this may require modification.execute_linter(): Attempts to perform in the same way as svlint does. If svlint is modified, then this may require modification.plugin_test(): Called by the functions written bybuild.rs. Should not normally require modification.
- A collection of SystemVerilog testcase files in
testcases/(fail|pass)/. Naturally, you must create your own testcases for your own plugin rules. To add a SystemVerilog test file, simply copy it totestcases/pass/if it must pass all of the plugin's rules, or totestcases/fail/if it must fail any of the plugin's rules. - The build script (
build.rs) which uses the testcase files to produce test functions just before the main compilation.