Skip to content

Commit e0da3f7

Browse files
committed
Create standalone function to build the shared library.
1 parent abbc7a5 commit e0da3f7

File tree

2 files changed

+87
-63
lines changed

2 files changed

+87
-63
lines changed

exe/arduino_ci.rb

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -423,47 +423,51 @@ def perform_unit_tests(cpp_library, file_config)
423423
puts
424424
compilers.each do |gcc_binary|
425425
# before compiling the tests, build a shared library of everything except the test code
426-
attempt_multiline("Build shared library with #{gcc_binary} for #{p}") do
427-
exe = cpp_library.build_for_test_with_configuration(
428-
nil, # nil is a flag that we are building the shared library with everything else
429-
config.aux_libraries_for_unittest,
430-
gcc_binary,
431-
config.gcc_config(p)
432-
)
433-
puts
434-
unless exe
435-
puts "Last command: #{cpp_library.last_cmd}"
436-
puts cpp_library.last_out
437-
puts cpp_library.last_err
438-
next false
439-
end
440-
true
441-
end
442-
# now build and run each test using the shared library build above
443-
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
444-
unittest_name = unittest_path.basename.to_s
445-
puts "--------------------------------------------------------------------------------"
446-
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary} for #{p}") do
447-
exe = cpp_library.build_for_test_with_configuration(
448-
unittest_path,
449-
config.aux_libraries_for_unittest,
450-
gcc_binary,
451-
config.gcc_config(p)
452-
)
453-
puts
454-
unless exe
455-
puts "Last command: #{cpp_library.last_cmd}"
456-
puts cpp_library.last_out
457-
puts cpp_library.last_err
458-
next false
426+
if build_shared_library(gcc_binary, p, config, cpp_library)
427+
# now build and run each test using the shared library build above
428+
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
429+
unittest_name = unittest_path.basename.to_s
430+
puts "--------------------------------------------------------------------------------"
431+
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary} for #{p}") do
432+
exe = cpp_library.build_for_test_with_configuration(
433+
unittest_path,
434+
config.aux_libraries_for_unittest,
435+
gcc_binary,
436+
config.gcc_config(p)
437+
)
438+
puts
439+
unless exe
440+
puts "Last command: #{cpp_library.last_cmd}"
441+
puts cpp_library.last_out
442+
puts cpp_library.last_err
443+
next false
444+
end
445+
cpp_library.run_test_file(exe)
459446
end
460-
cpp_library.run_test_file(exe)
461447
end
462448
end
463449
end
464450
end
465451
end
466452

453+
def build_shared_library(gcc_binary, platform, config, cpp_library)
454+
attempt_multiline("Build shared library with #{gcc_binary} for #{platform}") do
455+
exe = cpp_library.build_share_library_with_configuration(
456+
config.aux_libraries_for_unittest,
457+
gcc_binary,
458+
config.gcc_config(platform)
459+
)
460+
puts
461+
unless exe
462+
puts "Last command: #{cpp_library.last_cmd}"
463+
puts cpp_library.last_out
464+
puts cpp_library.last_err
465+
return false
466+
end
467+
return true
468+
end
469+
end
470+
467471
def perform_example_compilation_tests(cpp_library, config)
468472
phase("Compilation of example sketches")
469473
if @cli_options[:skip_compilation]

lib/arduino_ci/cpp_library.rb

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
CI_CPP_DIR = Pathname.new(__dir__).parent.parent + "cpp"
1010
ARDUINO_HEADER_DIR = CI_CPP_DIR + "arduino"
1111
UNITTEST_HEADER_DIR = CI_CPP_DIR + "unittest"
12+
LIBRARY_NAME = "arduino"
13+
BUILD_DIR = "#{Dir.pwd}/.arduino_ci" # hide build artifacts
14+
1215

1316
module ArduinoCI
1417

@@ -485,31 +488,53 @@ def test_args(aux_libraries, ci_gcc_config)
485488
#
486489
# The dependent libraries configuration is appended with data from library.properties internal to the library under test
487490
#
488-
# @param test_file [Pathname] The path to the file containing the unit tests (nil to compile application as shared library)
491+
# @param test_file [Pathname] The path to the file containing the unit tests
489492
# @param aux_libraries [Array<Pathname>] The external Arduino libraries required by this project
490493
# @param ci_gcc_config [Hash] The GCC config object
491494
# @return [Pathname] path to the compiled test executable
492495
def build_for_test_with_configuration(test_file, aux_libraries, gcc_binary, ci_gcc_config)
493-
build_dir = "#{Dir.pwd}/.arduino_ci" # hide build artifacts
494-
Dir.mkdir build_dir unless File.exist?(build_dir)
495-
lib_name = "arduino"
496+
executable = Pathname.new("#{BUILD_DIR}/#{test_file.basename}.bin").expand_path
497+
File.delete(executable) if File.exist?(executable)
498+
arg_sets = ["-std=c++0x", "-o", executable.to_s, "-L#{BUILD_DIR}", "-DARDUINO=100"]
499+
if libasan?(gcc_binary)
500+
arg_sets << [ # Stuff to help with dynamic memory mishandling
501+
"-g", "-O1",
502+
"-fno-omit-frame-pointer",
503+
"-fno-optimize-sibling-calls",
504+
"-fsanitize=address"
505+
]
506+
end
507+
arg_sets << @test_args
508+
arg_sets << [test_file.to_s, "-l#{LIBRARY_NAME}"]
509+
args = arg_sets.flatten(1)
510+
return nil unless run_gcc(gcc_binary, *args)
511+
512+
artifacts << executable
513+
executable
514+
end
515+
516+
# build a shared library to be used by each test
517+
#
518+
# The dependent libraries configuration is appended with data from library.properties internal to the library under test
519+
#
520+
# @param aux_libraries [Array<Pathname>] The external Arduino libraries required by this project
521+
# @param ci_gcc_config [Hash] The GCC config object
522+
# @return [Pathname] path to the compiled test executable
523+
def build_share_library_with_configuration(aux_libraries, gcc_binary, ci_gcc_config)
524+
Dir.mkdir BUILD_DIR unless File.exist?(BUILD_DIR)
496525
if OS.windows?
497-
full_lib_name = "#{build_dir}/lib#{lib_name}.dll"
498526
flag = ENV["PATH"].include? ";"
499-
ENV["PATH"] = build_dir + (flag ? ";" : ":") + ENV["PATH"] unless ENV["PATH"].include? build_dir
527+
ENV["PATH"] = BUILD_DIR + (flag ? ";" : ":") + ENV["PATH"] unless ENV["PATH"].include? build_dir
528+
suffix = "dll"
500529
else
501-
full_lib_name = "#{build_dir}/lib#{lib_name}.so"
502-
ENV["LD_LIBRARY_PATH"] = build_dir
503-
end
504-
arg_sets = ["-std=c++0x"]
505-
if test_file.nil?
506-
executable = Pathname.new(full_lib_name).expand_path
507-
arg_sets << ["-shared", "-fPIC", "-Wl,-undefined,dynamic_lookup"]
508-
else
509-
executable = Pathname.new("#{build_dir}/unittest_#{test_file.basename}.bin").expand_path
530+
ENV["LD_LIBRARY_PATH"] = BUILD_DIR
531+
suffix = "so"
510532
end
533+
full_lib_name = "#{BUILD_DIR}/lib#{LIBRARY_NAME}.#{suffix}"
534+
executable = Pathname.new(full_lib_name).expand_path
511535
File.delete(executable) if File.exist?(executable)
512-
arg_sets << ["-o", executable.to_s, "-L#{build_dir}", "-DARDUINO=100"]
536+
arg_sets = ["-std=c++0x", "-shared", "-fPIC", "-Wl,-undefined,dynamic_lookup",
537+
"-o", executable.to_s, "-L#{BUILD_DIR}", "-DARDUINO=100"]
513538
if libasan?(gcc_binary)
514539
arg_sets << [ # Stuff to help with dynamic memory mishandling
515540
"-g", "-O1",
@@ -522,19 +547,14 @@ def build_for_test_with_configuration(test_file, aux_libraries, gcc_binary, ci_g
522547
# combine library.properties defs (if existing) with config file.
523548
# 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
524549
# the following two take some time, so are cached when we build the shared library
525-
@full_dependencies ||= all_arduino_library_dependencies!(aux_libraries)
526-
@test_args ||= test_args(@full_dependencies, ci_gcc_config)
527-
arg_sets << @test_args # used cached value since building full set of include directories can take time
528-
529-
if File.exist?(full_lib_name) # add the test file and the shared library
530-
arg_sets << [test_file.to_s, "-l#{lib_name}"] if test_file
531-
else # CPP files for the shared library
532-
arg_sets << cpp_files_arduino.map(&:to_s) # Arduino.cpp, Godmode.cpp, and stdlib.cpp
533-
arg_sets << cpp_files_unittest.map(&:to_s) # ArduinoUnitTests.cpp
534-
arg_sets << cpp_files.map(&:to_s) # CPP files for the primary application library under test
535-
arg_sets << cpp_files_libraries(@full_dependencies).map(&:to_s) # CPP files for all the libraries we depend on
536-
arg_sets << [test_file.to_s] if test_file
537-
end
550+
@full_dependencies = all_arduino_library_dependencies!(aux_libraries)
551+
@test_args = test_args(@full_dependencies, ci_gcc_config) # build full set of include directories to be cached for later
552+
553+
arg_sets << @test_args
554+
arg_sets << cpp_files_arduino.map(&:to_s) # Arduino.cpp, Godmode.cpp, and stdlib.cpp
555+
arg_sets << cpp_files_unittest.map(&:to_s) # ArduinoUnitTests.cpp
556+
arg_sets << cpp_files.map(&:to_s) # CPP files for the primary application library under test
557+
arg_sets << cpp_files_libraries(@full_dependencies).map(&:to_s) # CPP files for all the libraries we depend on
538558
args = arg_sets.flatten(1)
539559
return nil unless run_gcc(gcc_binary, *args)
540560

0 commit comments

Comments
 (0)