Skip to content

Commit

Permalink
Add Valgrind plugin
Browse files Browse the repository at this point in the history
This commit adds the Valgrind plugin to Ceedling. The plugin
implementation closely follows the Gcov plugin.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
  • Loading branch information
jamestiotio committed Sep 2, 2023
1 parent 6cbf73f commit a3ba518
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 0 deletions.
22 changes: 22 additions & 0 deletions plugins/valgrind/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ceedling-valgrind
=============

# Plugin Overview

Plugin for integrating Valgrind tool into Ceedling projects.

This plugin currently uses the compiled test executables as the target
executables to be executed under Valgrind. The normal test task _must_ be
run first for Valgrind to succeed.

## Installation

Valgrind can be installed by either building from source, which can be
obtained from [here](https://valgrind.org/downloads/), or by installing
the Valgrind package included in your Linux distribution.

## Example Usage

```sh
ceedling valgrind:all
```
22 changes: 22 additions & 0 deletions plugins/valgrind/config/defaults_valgrind.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

DEFAULT_VALGRIND = {
:executable => ENV['VALGRIND'].nil? ? FilePathUtils.os_executable_ext('valgrind').freeze : ENV['VALGRIND'].split[0],
:name => 'default_valgrind'.freeze,
:stderr_redirect => StdErrRedirect::NONE.freeze,
:background_exec => BackgroundExec::NONE.freeze,
:optional => false.freeze,
:arguments => [
"--leak-check=full".freeze,
"--show-reachable=yes".freeze,
"--show-leak-kinds=all".freeze,
"--track-origins=yes".freeze,
"--errors-for-leak-kinds=all".freeze,
"${1}".freeze
].freeze
}

def get_default_config
return :tools => {
:valgrind => DEFAULT_VALGRIND
}
end
23 changes: 23 additions & 0 deletions plugins/valgrind/lib/valgrind.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'ceedling/plugin'
require 'ceedling/constants'
require 'valgrind_constants'

class Valgrind < Plugin
attr_reader :config

def setup
@result_list = []

@config = {
:project_test_build_output_path => VALGRIND_BUILD_OUTPUT_PATH
}

@plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
end
end

# end blocks always executed following rake run
END {
# cache our input configurations to use in comparison upon next execution
@ceedling[:cacheinator].cache_test_config(@ceedling[:setupinator].config_hash) if @ceedling[:task_invoker].invoked?(/^#{VALGRIND_TASK_ROOT}/)
}
7 changes: 7 additions & 0 deletions plugins/valgrind/lib/valgrind_constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

VALGRIND_ROOT_NAME = 'valgrind'.freeze
VALGRIND_TASK_ROOT = VALGRIND_ROOT_NAME + ':'
VALGRIND_SYM = VALGRIND_ROOT_NAME.to_sym unless defined?(VALGRIND_SYM)

VALGRIND_BUILD_PATH = File.join(PROJECT_BUILD_ROOT, "test")
VALGRIND_BUILD_OUTPUT_PATH = File.join(VALGRIND_BUILD_PATH, "out")
49 changes: 49 additions & 0 deletions plugins/valgrind/valgrind.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
directory(VALGRIND_BUILD_OUTPUT_PATH)

CLEAN.include(File.join(VALGRIND_BUILD_OUTPUT_PATH, '*'))

CLOBBER.include(File.join(VALGRIND_BUILD_PATH, '**/*'))

task directories: [VALGRIND_BUILD_OUTPUT_PATH]

namespace VALGRIND_SYM do
task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{VALGRIND_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")

desc 'Run Valgrind for all tests'
task all: [:test_deps] do
@ceedling[:configurator].replace_flattened_config(@ceedling[VALGRIND_SYM].config)
COLLECTION_ALL_TESTS.each do |test|
executable = @ceedling[:file_path_utils].form_test_executable_filepath(test)
command = @ceedling[:tool_executor].build_command_line(TOOLS_VALGRIND, [], executable)
@ceedling[:streaminator].stdout_puts("\nINFO: #{command[:line]}\n\n")
@ceedling[:tool_executor].exec(command[:line], command[:options])
end
@ceedling[:configurator].restore_config
end

desc 'Run Valgrind for a single test or executable ([*] real test or source file name, no path).'
task :* do
message = "\nOops! '#{VALGRIND_ROOT_NAME}:*' isn't a real task. " \
"Use a real test or source file name (no path) in place of the wildcard.\n" \
"Example: rake #{VALGRIND_ROOT_NAME}:foo.c\n\n"

@ceedling[:streaminator].stdout_puts(message)
end

# use a rule to increase efficiency for large projects
# valgrind test tasks by regex
rule(/^#{VALGRIND_TASK_ROOT}\S+$/ => [
proc do |task_name|
test = task_name.sub(/#{VALGRIND_TASK_ROOT}/, '')
test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX)
@ceedling[:file_finder].find_test_from_file_path(test)
end
]) do test
@ceedling[:configurator].replace_flattened_config(@ceedling[VALGRIND_SYM].config)
executable = @ceedling[:file_path_utils].form_test_executable_filepath(test.source)
command = @ceedling[:tool_executor].build_command_line(TOOLS_VALGRIND, [], executable)
@ceedling[:streaminator].stdout_puts("\nINFO: #{command[:line]}\n\n")
@ceedling[:tool_executor].exec(command[:line], command[:options])
@ceedling[:configurator].restore_config
end
end

0 comments on commit a3ba518

Please sign in to comment.