Class: ArduinoCI::CppLibrary
- Inherits:
-
Object
- Object
- ArduinoCI::CppLibrary
- Defined in:
- lib/arduino_ci/cpp_library.rb
Overview
Information about an Arduino CPP library, specifically for compilation purposes
Constant Summary collapse
- LIBRARY_PROPERTIES_FILE =
Returns The official library properties file name.
"library.properties".freeze
Instance Attribute Summary collapse
-
#artifacts ⇒ Array<Pathname>
readonly
The set of artifacts created by this class (note: incomplete!).
-
#backend ⇒ ArduinoBackend
readonly
The backend support for this library.
-
#exclude_dirs ⇒ Array<Pathname>
The set of directories that should be excluded from compilation.
-
#last_cmd ⇒ String
readonly
The last command.
-
#last_err ⇒ String
readonly
STDERR from the last command.
-
#last_out ⇒ String
readonly
STDOUT from the last command.
-
#name ⇒ String
readonly
The “official” name of the library, which can include spaces (in a way that the lib dir won’t).
-
#vendor_bundle_cache ⇒ Array<Pathname>
readonly
Directories suspected of being vendor-bundle.
Class Method Summary collapse
-
.library_directory_name(friendly_name) ⇒ String
Generate a guess as to the on-disk (coerced character) name of this library.
Instance Method Summary collapse
-
#add_build_dirs_to_env ⇒ Object
Add build dir to path.
-
#all_arduino_library_dependencies!(additional_libraries = []) ⇒ Array<String>
Arduino library dependencies all the way down, installing if they are not present.
-
#arduino_library_dependencies ⇒ Array<String>
Get a list of all dependencies as defined in library.properties.
-
#arduino_library_src_dirs(aux_libraries) ⇒ Array<Pathname>
Arduino library directories containing sources – only those of the dependencies.
-
#build_for_test(test_file, gcc_binary) ⇒ Pathname
build a file for running a test of the given unit test file.
-
#build_shared_library(aux_libraries, gcc_binary, ci_gcc_config) ⇒ Pathname
build a shared library to be used by each test.
-
#code_files_in(some_dir, extensions) ⇒ Array<Pathname>
Get a list of all CPP source files in a directory and its subdirectories.
-
#code_files_in_recursive(some_dir, extensions) ⇒ Array<Pathname>
Get a list of all CPP source files in a directory and its subdirectories.
-
#cpp_files ⇒ Array<Pathname>
CPP files that are part of the project library under test.
-
#cpp_files_arduino ⇒ Array<Pathname>
CPP files that are part of the arduino mock library we’re providing.
-
#cpp_files_libraries(aux_libraries) ⇒ Array<Pathname>
CPP files that are part of the 3rd-party libraries we’re including.
-
#cpp_files_unittest ⇒ Array<Pathname>
CPP files that are part of the unit test library we’re providing.
-
#define_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments for defines (e.g. -Dhave_something).
-
#example_sketches ⇒ Array<String>
Example sketch files.
-
#examples_dir ⇒ String
The parent directory of all examples.
-
#exclude_dir ⇒ Array<Pathname>
Returns the Pathnames for all paths to exclude from testing and compilation.
-
#feature_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments for features (e.g. -fno-weak).
-
#flag_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments as-is.
-
#gcc_version(gcc_binary) ⇒ String
Return the GCC version.
-
#header_dirs ⇒ Array<Pathname>
Find all directories in the project library that include C++ header files.
-
#header_files ⇒ Array<Pathname>
Header files that are part of the project library under test.
-
#in_exclude_dir?(sourcefile_path) ⇒ bool
Guess whether a file is part of any @excludes_dir dir (indicating library compilation should ignore it).
-
#in_tests_dir?(sourcefile_path) ⇒ bool
Guess whether a file is part of the tests/ dir (indicating library compilation should ignore it).
-
#include_args(aux_libraries) ⇒ Array<String>
GCC command line arguments for including aux libraries.
-
#info ⇒ Hash
information about the library as reported by the backend.
-
#initialize(friendly_name, backend) ⇒ CppLibrary
constructor
A new instance of CppLibrary.
-
#install(version = nil, recursive = false) ⇒ bool
install a library by name.
-
#installed? ⇒ bool
Determine whether a library is present in the lib dir.
-
#libasan?(gcc_binary) ⇒ Boolean
Check whether libasan (and by extension -fsanitizer=address) is supported.
-
#library_properties ⇒ LibraryProperties
Library properties.
-
#library_properties? ⇒ bool
Whether library.properties definitions for this library exist.
-
#library_properties_path ⇒ Pathname
The expected path to the library.properties file (i.e. even if it does not exist).
-
#name_on_disk ⇒ String
Generate a guess as to the on-disk (coerced character) name of this library.
-
#one_point_five? ⇒ bool
Decide whether this is a 1.5-compatible library.
-
#path ⇒ Pathname
Get the path to this library, whether or not it exists.
-
#print_stack_dump(executable) ⇒ Object
print any found stack dumps.
-
#run_gcc(gcc_binary, *args, **kwargs) ⇒ Object
wrapper for the GCC command.
-
#run_test_file(executable) ⇒ bool
run a test file.
-
#source_files(extensions) ⇒ Array<Pathname>
Source files that are part of the library under test.
-
#test_args(aux_libraries, ci_gcc_config) ⇒ Array<String>
All non-CPP GCC command line args for building any unit test.
-
#test_files ⇒ Array<Pathname>
The files provided by the user that contain unit tests.
-
#tests_dir ⇒ Pathname
The directory where we expect to find unit test definitions provided by the user.
-
#vendor_bundle?(some_path) ⇒ bool
Guess whether a file is part of the vendor bundle (indicating we should ignore it).
-
#warning_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments for warning (e.g. -Wall).
Constructor Details
#initialize(friendly_name, backend) ⇒ CppLibrary
Returns a new instance of CppLibrary.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/arduino_ci/cpp_library.rb', line 50 def initialize(friendly_name, backend) raise ArgumentError, "friendly_name is not a String (got #{friendly_name.class})" unless friendly_name.is_a? String raise ArgumentError, 'backend is not a ArduinoBackend' unless backend.is_a? ArduinoBackend @name = friendly_name @backend = backend @info_cache = nil @artifacts = [] @last_err = "" @last_out = "" @last_msg = "" @has_libasan_cache = {} @vendor_bundle_cache = nil @exclude_dirs = [] end |
Instance Attribute Details
#artifacts ⇒ Array<Pathname> (readonly)
Returns The set of artifacts created by this class (note: incomplete!).
31 32 33 |
# File 'lib/arduino_ci/cpp_library.rb', line 31 def artifacts @artifacts end |
#backend ⇒ ArduinoBackend (readonly)
Returns The backend support for this library.
28 29 30 |
# File 'lib/arduino_ci/cpp_library.rb', line 28 def backend @backend end |
#exclude_dirs ⇒ Array<Pathname>
Returns The set of directories that should be excluded from compilation.
34 35 36 |
# File 'lib/arduino_ci/cpp_library.rb', line 34 def exclude_dirs @exclude_dirs end |
#last_cmd ⇒ String (readonly)
Returns the last command.
43 44 45 |
# File 'lib/arduino_ci/cpp_library.rb', line 43 def last_cmd @last_cmd end |
#last_err ⇒ String (readonly)
Returns STDERR from the last command.
37 38 39 |
# File 'lib/arduino_ci/cpp_library.rb', line 37 def last_err @last_err end |
#last_out ⇒ String (readonly)
Returns STDOUT from the last command.
40 41 42 |
# File 'lib/arduino_ci/cpp_library.rb', line 40 def last_out @last_out end |
#name ⇒ String (readonly)
Returns The “official” name of the library, which can include spaces (in a way that the lib dir won’t).
25 26 27 |
# File 'lib/arduino_ci/cpp_library.rb', line 25 def name @name end |
#vendor_bundle_cache ⇒ Array<Pathname> (readonly)
Returns Directories suspected of being vendor-bundle.
46 47 48 |
# File 'lib/arduino_ci/cpp_library.rb', line 46 def vendor_bundle_cache @vendor_bundle_cache end |
Class Method Details
.library_directory_name(friendly_name) ⇒ String
Generate a guess as to the on-disk (coerced character) name of this library
@TODO: delegate this to the backend in some way? It uses “official” names for install, but dir names in lists :(
71 72 73 |
# File 'lib/arduino_ci/cpp_library.rb', line 71 def self.library_directory_name(friendly_name) friendly_name.tr(" ", "_") end |
Instance Method Details
#add_build_dirs_to_env ⇒ Object
Add build dir to path
517 518 519 520 521 522 523 |
# File 'lib/arduino_ci/cpp_library.rb', line 517 def add_build_dirs_to_env ENV["LD_LIBRARY_PATH"] = BUILD_DIR unless OS.windows? paths = ENV["PATH"].split(File::PATH_SEPARATOR) return if paths.include?(BUILD_DIR) ENV["PATH"] = BUILD_DIR + File::PATH_SEPARATOR + ENV["PATH"] if OS.windows? end |
#all_arduino_library_dependencies!(additional_libraries = []) ⇒ Array<String>
Arduino library dependencies all the way down, installing if they are not present
407 408 409 410 411 412 413 414 415 416 |
# File 'lib/arduino_ci/cpp_library.rb', line 407 def all_arduino_library_dependencies!(additional_libraries = []) # Pull in all possible places that headers could live, according to the spec: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification recursive = (additional_libraries + arduino_library_dependencies).map do |n| other_lib = self.class.new(n, @backend) other_lib.install unless other_lib.installed? other_lib.all_arduino_library_dependencies! end.flatten (additional_libraries + recursive).uniq end |
#arduino_library_dependencies ⇒ Array<String>
Get a list of all dependencies as defined in library.properties
398 399 400 401 402 403 |
# File 'lib/arduino_ci/cpp_library.rb', line 398 def arduino_library_dependencies return [] unless library_properties? return [] if library_properties.depends.nil? library_properties.depends end |
#arduino_library_src_dirs(aux_libraries) ⇒ Array<Pathname>
Arduino library directories containing sources – only those of the dependencies
420 421 422 |
# File 'lib/arduino_ci/cpp_library.rb', line 420 def arduino_library_src_dirs(aux_libraries) all_arduino_library_dependencies!(aux_libraries).map { |l| self.class.new(l, @backend).header_dirs }.flatten.uniq end |
#build_for_test(test_file, gcc_binary) ⇒ Pathname
build a file for running a test of the given unit test file
The dependent libraries configuration is appended with data from library.properties internal to the library under test
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
# File 'lib/arduino_ci/cpp_library.rb', line 495 def build_for_test(test_file, gcc_binary) executable = Pathname.new("#{BUILD_DIR}/#{test_file.basename}.bin"). File.delete(executable) if File.exist?(executable) arg_sets = ["-std=c++0x", "-o", executable.to_s, "-L#{BUILD_DIR}", "-DARDUINO=100"] if libasan?(gcc_binary) arg_sets << [ # Stuff to help with dynamic memory mishandling "-g", "-O1", "-fno-omit-frame-pointer", "-fno-optimize-sibling-calls", "-fsanitize=address" ] end arg_sets << @test_args arg_sets << [test_file.to_s, "-l#{LIBRARY_NAME}"] args = arg_sets.flatten(1) return nil unless run_gcc(gcc_binary, *args) artifacts << executable executable end |
#build_shared_library(aux_libraries, gcc_binary, ci_gcc_config) ⇒ Pathname
build a shared library to be used by each test
The dependent libraries configuration is appended with data from library.properties internal to the library under test
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
# File 'lib/arduino_ci/cpp_library.rb', line 533 def build_shared_library(aux_libraries, gcc_binary, ci_gcc_config) FileUtils.mkdir_p(BUILD_DIR) add_build_dirs_to_env suffix = OS.windows? ? "dll" : "so" full_lib_name = "#{BUILD_DIR}/lib#{LIBRARY_NAME}.#{suffix}" executable = Pathname.new(full_lib_name). File.delete(executable) if File.exist?(executable) arg_sets = ["-std=c++0x", "-shared", "-fPIC", "-Wl,-undefined,dynamic_lookup", "-o", executable.to_s, "-L#{BUILD_DIR}", "-DARDUINO=100"] if libasan?(gcc_binary) arg_sets << [ # Stuff to help with dynamic memory mishandling "-g", "-O1", "-fno-omit-frame-pointer", "-fno-optimize-sibling-calls", "-fsanitize=address" ] end # combine library.properties defs (if existing) with config file. # TODO: as much as I'd like to rely only on the properties file(s), I think that would prevent testing 1.0-spec libs # the following two take some time, so are cached when we build the shared library @full_dependencies = all_arduino_library_dependencies!(aux_libraries) @test_args = test_args(@full_dependencies, ci_gcc_config) # build full set of include directories to be cached for later arg_sets << @test_args arg_sets << cpp_files_arduino.map(&:to_s) # Arduino.cpp, Godmode.cpp, and stdlib.cpp arg_sets << cpp_files_unittest.map(&:to_s) # ArduinoUnitTests.cpp arg_sets << cpp_files.map(&:to_s) # CPP files for the primary application library under test arg_sets << cpp_files_libraries(@full_dependencies).map(&:to_s) # CPP files for all the libraries we depend on args = arg_sets.flatten(1) return nil unless run_gcc(gcc_binary, *args) artifacts << executable executable end |
#code_files_in(some_dir, extensions) ⇒ Array<Pathname>
Get a list of all CPP source files in a directory and its subdirectories
281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/arduino_ci/cpp_library.rb', line 281 def code_files_in(some_dir, extensions) raise ArgumentError, 'some_dir is not a Pathname' unless some_dir.is_a? Pathname full_dir = path + some_dir return [] unless full_dir.exist? && full_dir.directory? files = full_dir.children.reject(&:directory?) cpp = files.select { |path| extensions.include?(path.extname.downcase) } not_hidden = cpp.reject { |path| path.basename.to_s.start_with?(".") } not_hidden.sort_by(&:to_s) end |
#code_files_in_recursive(some_dir, extensions) ⇒ Array<Pathname>
Get a list of all CPP source files in a directory and its subdirectories
297 298 299 300 301 302 |
# File 'lib/arduino_ci/cpp_library.rb', line 297 def code_files_in_recursive(some_dir, extensions) raise ArgumentError, 'some_dir is not a Pathname' unless some_dir.is_a? Pathname return [] unless some_dir.exist? && some_dir.directory? Find.find(some_dir).map { |p| Pathname.new(p) }.select(&:directory?).map { |d| code_files_in(d, extensions) }.flatten end |
#cpp_files ⇒ Array<Pathname>
CPP files that are part of the project library under test
328 329 330 |
# File 'lib/arduino_ci/cpp_library.rb', line 328 def cpp_files source_files(CPP_EXTENSIONS) end |
#cpp_files_arduino ⇒ Array<Pathname>
CPP files that are part of the arduino mock library we’re providing
334 335 336 |
# File 'lib/arduino_ci/cpp_library.rb', line 334 def cpp_files_arduino code_files_in(ARDUINO_HEADER_DIR, CPP_EXTENSIONS) end |
#cpp_files_libraries(aux_libraries) ⇒ Array<Pathname>
CPP files that are part of the 3rd-party libraries we’re including
347 348 349 |
# File 'lib/arduino_ci/cpp_library.rb', line 347 def cpp_files_libraries(aux_libraries) arduino_library_src_dirs(aux_libraries).map { |d| code_files_in(d, CPP_EXTENSIONS) }.flatten.uniq end |
#cpp_files_unittest ⇒ Array<Pathname>
CPP files that are part of the unit test library we’re providing
340 341 342 |
# File 'lib/arduino_ci/cpp_library.rb', line 340 def cpp_files_unittest code_files_in(UNITTEST_HEADER_DIR, CPP_EXTENSIONS) end |
#define_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments for defines (e.g. -Dhave_something)
457 458 459 460 461 |
# File 'lib/arduino_ci/cpp_library.rb', line 457 def define_args(ci_gcc_config) return [] if ci_gcc_config[:defines].nil? ci_gcc_config[:defines].map { |d| "-D#{d}" } end |
#example_sketches ⇒ Array<String>
Returns Example sketch files.
138 139 140 141 142 |
# File 'lib/arduino_ci/cpp_library.rb', line 138 def example_sketches examples = info["library"].fetch("examples", []) reported_dirs = examples.map(&Pathname::method(:new)) reported_dirs.map { |e| e + e.basename.sub_ext(".ino") }.select(&:exist?).sort_by(&:to_s) end |
#examples_dir ⇒ String
Returns The parent directory of all examples.
90 91 92 |
# File 'lib/arduino_ci/cpp_library.rb', line 90 def examples_dir path + "examples" end |
#exclude_dir ⇒ Array<Pathname>
Returns the Pathnames for all paths to exclude from testing and compilation
353 354 355 |
# File 'lib/arduino_ci/cpp_library.rb', line 353 def exclude_dir @exclude_dirs.map { |p| Pathname.new(path) + p }.select(&:exist?) end |
#feature_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments for features (e.g. -fno-weak)
439 440 441 442 443 |
# File 'lib/arduino_ci/cpp_library.rb', line 439 def feature_args(ci_gcc_config) return [] if ci_gcc_config[:features].nil? ci_gcc_config[:features].map { |f| "-f#{f}" } end |
#flag_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments as-is
466 467 468 469 470 |
# File 'lib/arduino_ci/cpp_library.rb', line 466 def flag_args(ci_gcc_config) return [] if ci_gcc_config[:flags].nil? ci_gcc_config[:flags] end |
#gcc_version(gcc_binary) ⇒ String
Return the GCC version
390 391 392 393 394 |
# File 'lib/arduino_ci/cpp_library.rb', line 390 def gcc_version(gcc_binary) return nil unless run_gcc(gcc_binary, "-v") @last_err end |
#header_dirs ⇒ Array<Pathname>
Find all directories in the project library that include C++ header files
371 372 373 374 375 376 |
# File 'lib/arduino_ci/cpp_library.rb', line 371 def header_dirs unbundled = header_files.reject { |path| vendor_bundle?(path) } unexcluded = unbundled.reject { |path| in_exclude_dir?(path) } files = unexcluded.select { |path| HPP_EXTENSIONS.include?(path.extname.downcase) } files.map(&:dirname).uniq end |
#header_files ⇒ Array<Pathname>
Header files that are part of the project library under test
322 323 324 |
# File 'lib/arduino_ci/cpp_library.rb', line 322 def header_files source_files(HPP_EXTENSIONS) end |
#in_exclude_dir?(sourcefile_path) ⇒ bool
Guess whether a file is part of any @excludes_dir dir (indicating library compilation should ignore it).
253 254 255 256 257 258 259 260 |
# File 'lib/arduino_ci/cpp_library.rb', line 253 def in_exclude_dir?(sourcefile_path) # we could do this but some rubies don't return an enumerator for ascend # path.ascend.any? { |part| tests_dir_aliases.include?(part) } sourcefile_path.ascend do |part| return true if exclude_dir.any? { |p| p.realpath == part.realpath } end false end |
#in_tests_dir?(sourcefile_path) ⇒ bool
Guess whether a file is part of the tests/ dir (indicating library compilation should ignore it).
237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/arduino_ci/cpp_library.rb', line 237 def in_tests_dir?(sourcefile_path) return false unless tests_dir.exist? tests_dir_aliases = [tests_dir, tests_dir.realpath] # we could do this but some rubies don't return an enumerator for ascend # path.ascend.any? { |part| tests_dir_aliases.include?(part) } sourcefile_path.ascend do |part| return true if tests_dir_aliases.include?(part) end false end |
#include_args(aux_libraries) ⇒ Array<String>
GCC command line arguments for including aux libraries
This function recursively collects the library directories of the dependencies
430 431 432 433 434 |
# File 'lib/arduino_ci/cpp_library.rb', line 430 def include_args(aux_libraries) all_aux_include_dirs = arduino_library_src_dirs(aux_libraries) places = [ARDUINO_HEADER_DIR, UNITTEST_HEADER_DIR] + header_dirs + all_aux_include_dirs places.map { |d| "-I#{d}" } end |
#info ⇒ Hash
information about the library as reported by the backend
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/arduino_ci/cpp_library.rb', line 122 def info return nil unless installed? # note that if the library isn't found, we're going to do a lot of cache attempts... if @info_cache.nil? @info_cache = @backend.installed_libraries.find do |l| lib_info = l["library"] Pathname.new(lib_info["install_dir"]).realpath == path.realpath end end @info_cache end |
#install(version = nil, recursive = false) ⇒ bool
install a library by name
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/arduino_ci/cpp_library.rb', line 108 def install(version = nil, recursive = false) return true if installed? && !recursive fqln = version.nil? ? @name : "#{@name}@#{version}" result = if recursive @backend.run_and_capture("lib", "install", fqln) else @backend.run_and_capture("lib", "install", "--no-deps", fqln) end result[:success] end |
#installed? ⇒ bool
Determine whether a library is present in the lib dir
Note that ‘true` doesn’t guarantee that the library is valid/installed
and `false` doesn't guarantee that the library isn't built-in
100 101 102 |
# File 'lib/arduino_ci/cpp_library.rb', line 100 def installed? path.exist? || path.symlink? end |
#libasan?(gcc_binary) ⇒ Boolean
Check whether libasan (and by extension -fsanitizer=address) is supported
This requires compilation of a sample program, and will be cached
266 267 268 269 270 271 272 273 274 275 |
# File 'lib/arduino_ci/cpp_library.rb', line 266 def libasan?(gcc_binary) unless @has_libasan_cache.key?(gcc_binary) Tempfile.create(["arduino_ci_libasan_check", ".cpp"]) do |file| file.write "int main(){}" file.close @has_libasan_cache[gcc_binary] = run_gcc(gcc_binary, "-o", "/dev/null", "-fsanitize=address", file.path) end end @has_libasan_cache[gcc_binary] end |
#library_properties ⇒ LibraryProperties
Library properties
159 160 161 162 163 |
# File 'lib/arduino_ci/cpp_library.rb', line 159 def library_properties return nil unless library_properties? LibraryProperties.new(library_properties_path) end |
#library_properties? ⇒ bool
Whether library.properties definitions for this library exist
152 153 154 155 |
# File 'lib/arduino_ci/cpp_library.rb', line 152 def library_properties? lib_props = library_properties_path lib_props.exist? && lib_props.file? end |
#library_properties_path ⇒ Pathname
The expected path to the library.properties file (i.e. even if it does not exist)
146 147 148 |
# File 'lib/arduino_ci/cpp_library.rb', line 146 def library_properties_path path + LIBRARY_PROPERTIES_FILE end |
#name_on_disk ⇒ String
Generate a guess as to the on-disk (coerced character) name of this library
@TODO: delegate this to the backend in some way? It uses “official” names for install, but dir names in lists :(
79 80 81 |
# File 'lib/arduino_ci/cpp_library.rb', line 79 def name_on_disk self.class.library_directory_name(@name) end |
#one_point_five? ⇒ bool
Decide whether this is a 1.5-compatible library
This should be according to arduino.github.io/arduino-cli/latest/library-specification but we rely on the cli to decide for us
176 177 178 179 180 181 |
# File 'lib/arduino_ci/cpp_library.rb', line 176 def one_point_five? return false unless library_properties? src_dir = path + "src" src_dir.exist? && src_dir.directory? end |
#path ⇒ Pathname
Get the path to this library, whether or not it exists
85 86 87 |
# File 'lib/arduino_ci/cpp_library.rb', line 85 def path @backend.lib_dir + name_on_disk end |
#print_stack_dump(executable) ⇒ Object
print any found stack dumps
571 572 573 574 575 576 577 578 579 |
# File 'lib/arduino_ci/cpp_library.rb', line 571 def print_stack_dump(executable) possible_dumpfiles = [ executable.sub_ext("#{executable.extname}.stackdump") ] possible_dumpfiles.select(&:exist?).each do |dump| puts "========== Stack dump from #{dump}:" File.foreach(dump) { |line| print " #{line}" } end end |
#run_gcc(gcc_binary, *args, **kwargs) ⇒ Object
wrapper for the GCC command
379 380 381 382 383 384 385 386 |
# File 'lib/arduino_ci/cpp_library.rb', line 379 def run_gcc(gcc_binary, *args, **kwargs) full_args = [gcc_binary] + args @last_cmd = " $ #{full_args.join(' ')}" ret = Host.run_and_capture(*full_args, **kwargs) @last_err = ret[:err] @last_out = ret[:out] ret[:success] end |
#run_test_file(executable) ⇒ bool
run a test file
584 585 586 587 588 589 590 591 592 593 594 |
# File 'lib/arduino_ci/cpp_library.rb', line 584 def run_test_file(executable) @last_cmd = executable @last_out = "" @last_err = "" ret = Host.run_and_output(executable.to_s.shellescape) # print any stack traces found during a failure print_stack_dump(executable) unless ret ret end |
#source_files(extensions) ⇒ Array<Pathname>
Source files that are part of the library under test
307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/arduino_ci/cpp_library.rb', line 307 def source_files(extensions) source_dir = Pathname.new(info["library"]["source_dir"]) ret = if one_point_five? code_files_in_recursive(source_dir, extensions) else [source_dir, source_dir + "utility"].map { |d| code_files_in(d, extensions) }.flatten end # note to future troubleshooter: some of these tests may not be relevant, but at the moment at # least some of them are tied to existing features ret.reject { |p| vendor_bundle?(p) || in_tests_dir?(p) || in_exclude_dir?(p) } end |
#test_args(aux_libraries, ci_gcc_config) ⇒ Array<String>
All non-CPP GCC command line args for building any unit test. We leave out the CPP files so they can be included or not depending on whether we are building a shared library.
478 479 480 481 482 483 484 485 486 |
# File 'lib/arduino_ci/cpp_library.rb', line 478 def test_args(aux_libraries, ci_gcc_config) # TODO: something with libraries? ret = include_args(aux_libraries) unless ci_gcc_config.nil? cgc = ci_gcc_config ret = feature_args(cgc) + warning_args(cgc) + define_args(cgc) + flag_args(cgc) + ret end ret end |
#test_files ⇒ Array<Pathname>
The files provided by the user that contain unit tests
365 366 367 |
# File 'lib/arduino_ci/cpp_library.rb', line 365 def test_files code_files_in(tests_dir, CPP_EXTENSIONS) end |
#tests_dir ⇒ Pathname
The directory where we expect to find unit test definitions provided by the user
359 360 361 |
# File 'lib/arduino_ci/cpp_library.rb', line 359 def tests_dir Pathname.new(path) + "test" end |
#vendor_bundle?(some_path) ⇒ bool
Guess whether a file is part of the vendor bundle (indicating we should ignore it).
A safe way to do this seems to be to check whether any of the installed gems
appear to be a subdirectory of (but not equal to) the working directory.
That gets us the vendor directory (or multiple directories). We can check
if the given path is contained by any of those.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/arduino_ci/cpp_library.rb', line 192 def vendor_bundle?(some_path) # Cache bundle information, as it is (1) time consuming to fetch and (2) not going to change while we run if @vendor_bundle_cache.nil? bundle_info = Host.run_and_capture("bundle show --paths") if !bundle_info[:success] # if the bundle show command fails, assume there isn't a bundle @vendor_bundle_cache = false else # Get all the places where gems are stored. We combine a few things here: # by preemptively switching to the parent directory, we can both ensure that # we skip any gems that are equal to the working directory AND exploit some # commonality in the paths to cut down our search locations # # NOT CONFUSING THE WORKING DIRECTORY WITH VENDOR BUNDLE IS SUPER IMPORTANT # because if we do, we won't be able to run CI on this library itself. bundle_paths = bundle_info[:out].lines .map { |l| Pathname.new(l.chomp) } .select(&:exist?) .map(&:realpath) .map(&:parent) .uniq wd = Pathname.new(".").realpath @vendor_bundle_cache = bundle_paths.select do |gem_path| gem_path.ascend do |part| break true if wd == part end end end end # no bundle existed return false if @vendor_bundle_cache == false # With vendor bundles located, check this file against those @vendor_bundle_cache.any? do |gem_path| some_path.ascend do |part| break true if gem_path == part end end end |
#warning_args(ci_gcc_config) ⇒ Array<String>
GCC command line arguments for warning (e.g. -Wall)
448 449 450 451 452 |
# File 'lib/arduino_ci/cpp_library.rb', line 448 def warning_args(ci_gcc_config) return [] if ci_gcc_config[:warnings].nil? ci_gcc_config[:warnings].map { |w| "-W#{w}" } end |