|  | # # @param task [FFI::Compiler::CompileTask] task to configure | 
|  | def configure_common_compile_task(task) | 
|  | if FileUtils.pwd.include? 'ext' | 
|  | src_dir = '.' | 
|  | third_party_path = 'third_party/utf8_range' | 
|  | else | 
|  | src_dir = 'ext/google/protobuf_c' | 
|  | third_party_path = 'ext/google/protobuf_c/third_party/utf8_range' | 
|  | end | 
|  |  | 
|  | task.add_include_path third_party_path | 
|  | task.add_define 'NDEBUG' | 
|  | task.cflags << "-std=gnu99 -O3" | 
|  | [ | 
|  | :convert, :defs, :map, :message, :protobuf, :repeated_field, :wrap_memcpy | 
|  | ].each { |file| task.exclude << "/#{file}.c" } | 
|  | task.ext_dir = src_dir | 
|  | task.source_dirs = [src_dir] | 
|  | if RbConfig::CONFIG['target_os'] =~ /darwin|linux/ | 
|  | task.cflags << "-Wall -Wsign-compare -Wno-declaration-after-statement" | 
|  | end | 
|  | end | 
|  |  | 
|  | # FFI::CompilerTask's constructor walks the filesystem at task definition time | 
|  | # to create subtasks for each source file, so files from third_party must be | 
|  | # copied into place before the task is defined for it to work correctly. | 
|  | # TODO Is there a sane way to check for generated protos under lib too? | 
|  | def with_generated_files | 
|  | expected_path = FileUtils.pwd.include?('ext') ? 'third_party/utf8_range' : 'ext/google/protobuf_c/third_party/utf8_range' | 
|  | if File.directory?(expected_path) | 
|  | yield | 
|  | else | 
|  | task :default do | 
|  | # It is possible, especially in cases like the first invocation of | 
|  | # `rake test` following `rake clean` or a fresh checkout that the | 
|  | # `copy_third_party` task has been executed since initial task definition. | 
|  | # If so, run the task definition block now and invoke it explicitly. | 
|  | if File.directory?(expected_path) | 
|  | yield | 
|  | Rake::Task[:default].invoke | 
|  | else | 
|  | raise "Missing directory #{File.absolute_path(expected_path)}." + | 
|  | " Did you forget to run `rake copy_third_party` before building" + | 
|  | " native extensions?" | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | begin | 
|  | require "ffi-compiler/compile_task" | 
|  |  | 
|  | desc "Compile Protobuf library for FFI" | 
|  | namespace "ffi-protobuf" do | 
|  | with_generated_files do | 
|  | # Compile Ruby UPB separately in order to limit use of -DUPB_BUILD_API to one | 
|  | # compilation unit. | 
|  | desc "Compile UPB library for FFI" | 
|  | namespace "ffi-upb" do | 
|  | with_generated_files do | 
|  | FFI::Compiler::CompileTask.new('ruby-upb') do |c| | 
|  | configure_common_compile_task c | 
|  | c.add_define "UPB_BUILD_API" | 
|  | c.exclude << "/glue.c" | 
|  | c.exclude << "/shared_message.c" | 
|  | c.exclude << "/shared_convert.c" | 
|  | if RbConfig::CONFIG['target_os'] =~ /darwin|linux/ | 
|  | c.cflags << "-fvisibility=hidden" | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | FFI::Compiler::CompileTask.new 'protobuf_c_ffi' do |c| | 
|  | configure_common_compile_task c | 
|  | # Ruby UPB was already compiled with different flags. | 
|  | c.exclude << "/utf8_range.c" | 
|  | c.exclude << "/ruby-upb.c" | 
|  | end | 
|  |  | 
|  | # Setup dependencies so that the .o files generated by building ffi-upb are | 
|  | # available to link here. | 
|  | # TODO Can this be simplified? Can the single shared library be used | 
|  | # instead of the object files? | 
|  | protobuf_c_task = Rake::Task[:default] | 
|  | protobuf_c_shared_lib_task = Rake::Task[protobuf_c_task.prereqs.last] | 
|  | ruby_upb_shared_lib_task = Rake::Task[:"ffi-upb:default"].prereqs.first | 
|  | Rake::Task[ruby_upb_shared_lib_task].prereqs.each do |dependency| | 
|  | protobuf_c_shared_lib_task.prereqs.prepend dependency | 
|  | end | 
|  | end | 
|  | end | 
|  | rescue LoadError | 
|  | desc "Compile Protobuf library for FFI" | 
|  | namespace "ffi-protobuf" do | 
|  | task :default do | 
|  | warn "Skipping build of FFI; `gem install ffi-compiler` to enable." | 
|  | end | 
|  | end | 
|  | end |