Skip to content

Commit df60ca0

Browse files
committed
Move to own extension
1 parent f7bae27 commit df60ca0

File tree

11 files changed

+328
-347
lines changed

11 files changed

+328
-347
lines changed

Rakefile

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,16 @@ namespace :test do
5555

5656
candidates.each_key do |group|
5757
env = if group.empty?
58-
{}
59-
else
60-
gemfile = AppraisalConversion.to_bundle_gemfile(group)
61-
{'BUNDLE_GEMFILE' => gemfile}
62-
end
58+
{}
59+
else
60+
gemfile = AppraisalConversion.to_bundle_gemfile(group)
61+
{ 'BUNDLE_GEMFILE' => gemfile }
62+
end
6363
command = "bundle check || bundle install && bundle exec rake #{spec_task}"
6464
command += "'[#{spec_arguments}]'" if spec_arguments
6565

66-
total_executors = ENV.key?('CIRCLE_NODE_TOTAL') ? ENV['CIRCLE_NODE_TOTAL'].to_i : nil
67-
current_executor = ENV.key?('CIRCLE_NODE_INDEX') ? ENV['CIRCLE_NODE_INDEX'].to_i : nil
66+
total_executors = Datadog::DATADOG_ENV.key?('CIRCLE_NODE_TOTAL') ? Datadog::DATADOG_ENV['CIRCLE_NODE_TOTAL'].to_i : nil
67+
current_executor = Datadog::DATADOG_ENV.key?('CIRCLE_NODE_INDEX') ? Datadog::DATADOG_ENV['CIRCLE_NODE_INDEX'].to_i : nil
6868

6969
if total_executors && current_executor && total_executors > 1
7070
@execution_count ||= 0
@@ -82,10 +82,10 @@ desc 'Run RSpec'
8282
namespace :spec do
8383
# REMINDER: If adding a new task here, make sure also add it to the `Matrixfile`
8484
task all: [:main, :benchmark, :custom_cop,
85-
:graphql, :graphql_unified_trace_patcher, :graphql_trace_patcher, :graphql_tracing_patcher,
86-
:rails, :railsredis, :railsredis_activesupport, :railsactivejob,
87-
:elasticsearch, :http, :redis, :sidekiq, :sinatra, :hanami, :hanami_autoinstrument,
88-
:profiling, :core_with_libdatadog_api, :error_tracking, :open_feature]
85+
:graphql, :graphql_unified_trace_patcher, :graphql_trace_patcher, :graphql_tracing_patcher,
86+
:rails, :railsredis, :railsredis_activesupport, :railsactivejob,
87+
:elasticsearch, :http, :redis, :sidekiq, :sinatra, :hanami, :hanami_autoinstrument,
88+
:profiling, :core_with_libdatadog_api, :error_tracking, :open_feature]
8989

9090
desc '' # "Explicitly hiding from `rake -T`"
9191
RSpec::Core::RakeTask.new(:main) do |t, args|
@@ -228,7 +228,12 @@ namespace :spec do
228228
t.pattern = CORE_WITH_LIBDATADOG_API.join(', ')
229229
t.rspec_opts = args.to_a.join(' ')
230230
end.tap do |t|
231-
Rake::Task[t.name].enhance(["compile:libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}"])
231+
Rake::Task[t.name].enhance(
232+
[
233+
"compile:libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}",
234+
"compile:datadog_runtime_stacks.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}",
235+
]
236+
)
232237
end
233238
# rubocop:enable Style/MultilineBlockChain
234239

@@ -318,11 +323,18 @@ namespace :spec do
318323
rescue => e
319324
# Compilation failed (likely unsupported Ruby version) - tests will skip gracefully
320325
puts "Warning: libdatadog_api compilation failed: #{e.class}: #{e}"
321-
puts "DSM tests will be skipped for this Ruby version"
326+
puts 'DSM tests will be skipped for this Ruby version'
327+
end
328+
329+
task :compile_runtime_stacks do
330+
Rake::Task["compile:datadog_runtime_stacks.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}"].invoke
331+
rescue => e
332+
puts "Warning: datadog_runtime_stacks compilation failed: #{e.class}: #{e}"
333+
puts 'Runtime stack dependent tests will proceed without native runtime stacks support'
322334
end
323335

324336
DSM_ENABLED_LIBRARIES.each do |task_name|
325-
Rake::Task["spec:#{task_name}"].enhance([:compile_libdatadog_for_dsm])
337+
Rake::Task["spec:#{task_name}"].enhance([:compile_libdatadog_for_dsm, :compile_runtime_stacks])
326338
end
327339
end
328340

@@ -461,11 +473,11 @@ namespace :coverage do
461473
task :report do
462474
require 'simplecov'
463475

464-
resultset_files = Dir["#{ENV.fetch("COVERAGE_DIR", "coverage")}/.resultset.json"] +
465-
Dir["#{ENV.fetch("COVERAGE_DIR", "coverage")}/versions/**/.resultset.json"]
476+
resultset_files = Dir["#{Datadog::DATADOG_ENV.fetch('COVERAGE_DIR', 'coverage')}/.resultset.json"] +
477+
Dir["#{Datadog::DATADOG_ENV.fetch('COVERAGE_DIR', 'coverage')}/versions/**/.resultset.json"]
466478

467479
SimpleCov.collate resultset_files do
468-
coverage_dir "#{ENV.fetch("COVERAGE_DIR", "coverage")}/report"
480+
coverage_dir "#{Datadog::DATADOG_ENV.fetch('COVERAGE_DIR', 'coverage')}/report"
469481
formatter SimpleCov::Formatter::HTMLFormatter
470482
end
471483
end
@@ -475,11 +487,11 @@ namespace :coverage do
475487
require 'simplecov'
476488
require_relative 'spec/support/simplecov_fix'
477489

478-
versions = Dir["#{ENV.fetch("COVERAGE_DIR", "coverage")}/versions/*"].map { |f| File.basename(f) }
490+
versions = Dir["#{Datadog::DATADOG_ENV.fetch('COVERAGE_DIR', 'coverage')}/versions/*"].map { |f| File.basename(f) }
479491
versions.map do |version|
480492
puts "Generating report for: #{version}"
481-
SimpleCov.collate Dir["#{ENV.fetch("COVERAGE_DIR", "coverage")}/versions/#{version}/**/.resultset.json"] do
482-
coverage_dir "#{ENV.fetch("COVERAGE_DIR", "coverage")}/report/versions/#{version}"
493+
SimpleCov.collate Dir["#{Datadog::DATADOG_ENV.fetch('COVERAGE_DIR', 'coverage')}/versions/#{version}/**/.resultset.json"] do
494+
coverage_dir "#{Datadog::DATADOG_ENV.fetch('COVERAGE_DIR', 'coverage')}/report/versions/#{version}"
483495
formatter SimpleCov::Formatter::HTMLFormatter
484496
end
485497
end
@@ -499,6 +511,10 @@ NATIVE_EXTS = [
499511
ext.ext_dir = 'ext/libdatadog_api'
500512
end,
501513

514+
Rake::ExtensionTask.new("datadog_runtime_stacks.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}") do |ext|
515+
ext.ext_dir = 'ext/datadog_runtime_stacks'
516+
end,
517+
502518
Rake::ExtensionTask.new("datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}") do |ext|
503519
ext.ext_dir = 'ext/datadog_profiling_native_extension'
504520
end,

datadog.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Gem::Specification.new do |spec|
8383

8484
spec.extensions = [
8585
'ext/datadog_profiling_native_extension/extconf.rb',
86+
'ext/datadog_runtime_stacks/extconf.rb',
8687
'ext/libdatadog_api/extconf.rb'
8788
]
8889
end
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# rubocop:disable Style/StderrPuts
2+
# rubocop:disable Style/GlobalVars
3+
4+
require_relative "../libdatadog_extconf_helpers"
5+
6+
SKIPPED_REASON_FILE = "#{__dir__}/skipped_reason.txt".freeze
7+
# Not a problem if the file doesn't exist or we can't delete it
8+
begin
9+
File.delete(SKIPPED_REASON_FILE)
10+
rescue
11+
nil
12+
end
13+
14+
def skip_building_extension!(reason)
15+
$stderr.puts(
16+
"WARN: Skipping build of datadog_runtime_stacks (#{reason}). Runtime stack collection will not be available."
17+
)
18+
19+
fail_install_if_missing_extension = ENV["DD_FAIL_INSTALL_IF_MISSING_EXTENSION"].to_s.strip.downcase == "true"
20+
21+
if fail_install_if_missing_extension
22+
require "mkmf"
23+
Logging.message("[datadog] Failure cause: #{reason}")
24+
else
25+
File.write("Makefile", "all install clean: # dummy makefile that does nothing")
26+
end
27+
28+
exit
29+
end
30+
31+
if ENV["DD_NO_EXTENSION"].to_s.strip.downcase == "true"
32+
skip_building_extension!("the `DD_NO_EXTENSION` environment variable is/was set to `true` during installation")
33+
end
34+
skip_building_extension!("current Ruby VM is not supported") if RUBY_ENGINE != "ruby"
35+
skip_building_extension!("Microsoft Windows is not supported") if Gem.win_platform?
36+
37+
libdatadog_issue = Datadog::LibdatadogExtconfHelpers.load_libdatadog_or_get_issue
38+
skip_building_extension!("issue setting up `libdatadog` gem: #{libdatadog_issue}") if libdatadog_issue
39+
40+
require "mkmf"
41+
42+
# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
43+
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
44+
append_cflags "-Werror" if ENV["DATADOG_GEM_CI"] == "true"
45+
46+
# Older gcc releases may not default to C99 and we need to ask for this. This is also used:
47+
# * by upstream Ruby -- search for gnu99 in the codebase
48+
# * by msgpack, another datadog gem dependency
49+
append_cflags "-std=gnu99"
50+
51+
# Gets really noisy when we include the MJIT header, let's omit it
52+
append_cflags "-Wno-unused-function"
53+
54+
# Allow defining variables at any point in a function
55+
append_cflags "-Wno-declaration-after-statement"
56+
57+
# If we forget to include a Ruby header, the function call may still appear to work, but then
58+
# cause a segfault later. Let's ensure that never happens.
59+
append_cflags "-Werror-implicit-function-declaration"
60+
61+
# The native extension is not intended to expose any symbols/functions for other native libraries to use;
62+
append_cflags "-fvisibility=hidden"
63+
64+
# Avoid legacy C definitions
65+
append_cflags "-Wold-style-definition"
66+
67+
# Enable all other compiler warnings
68+
append_cflags "-Wall"
69+
append_cflags "-Wextra"
70+
71+
if ENV["DDTRACE_DEBUG"] == "true"
72+
$defs << "-DDD_DEBUG"
73+
CONFIG["optflags"] = "-O0"
74+
CONFIG["debugflags"] = "-ggdb3"
75+
end
76+
77+
# If we got here, libdatadog is available and loaded
78+
ENV["PKG_CONFIG_PATH"] = "#{ENV["PKG_CONFIG_PATH"]}:#{Libdatadog.pkgconfig_folder}"
79+
Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV["PKG_CONFIG_PATH"].inspect}\n")
80+
$stderr.puts("Using libdatadog #{Libdatadog::VERSION} from #{Libdatadog.pkgconfig_folder}")
81+
82+
unless pkg_config("datadog_profiling_with_rpath")
83+
Logging.message("[datadog] Ruby detected the pkg-config command is #{$PKGCONFIG.inspect}\n")
84+
85+
if Datadog::LibdatadogExtconfHelpers.pkg_config_missing?
86+
skip_building_extension!("the `pkg-config` system tool is missing")
87+
else
88+
skip_building_extension!("there was a problem in setting up the `libdatadog` dependency")
89+
end
90+
end
91+
92+
# Add Ruby version compatibility defines
93+
$defs << "-DNO_INT_FIRST_LINENO" if RUBY_VERSION < "3.2"
94+
$defs << "-DNO_RACTORS" if RUBY_VERSION < "3"
95+
$defs << "-DNO_RACTOR_HEADER_INCLUDE" if RUBY_VERSION < "3.3"
96+
97+
EXTENSION_NAME = "datadog_runtime_stacks.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}".freeze
98+
99+
# The MJIT header was introduced on 2.6 and removed on 3.3
100+
CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?("2.6", "2.7", "3.0.", "3.1.", "3.2.")
101+
102+
if CAN_USE_MJIT_HEADER
103+
mjit_header_file_name = "rb_mjit_min_header-#{RUBY_VERSION}.h"
104+
105+
# Validate that the mjit header can actually be compiled on this system
106+
original_common_headers = MakeMakefile::COMMON_HEADERS
107+
MakeMakefile::COMMON_HEADERS = "".freeze
108+
unless have_macro("RUBY_MJIT_H", mjit_header_file_name)
109+
skip_building_extension!("MJIT header compilation failed")
110+
end
111+
MakeMakefile::COMMON_HEADERS = original_common_headers
112+
113+
$defs << "-DRUBY_MJIT_HEADER='\"#{mjit_header_file_name}\"'"
114+
115+
create_header
116+
append_cflags "-Wunused-parameter"
117+
create_makefile EXTENSION_NAME
118+
else
119+
# For Rubies without MJIT header, use datadog-ruby_core_source gem
120+
create_header
121+
122+
require "datadog/ruby_core_source"
123+
dir_config("ruby") # allow user to pass in non-standard core include directory
124+
125+
# Workaround for mkmf issue with with_cppflags
126+
Datadog::RubyCoreSource.define_singleton_method(:with_cppflags) do |newflags, &block|
127+
super("#{newflags} #{$CPPFLAGS}", &block)
128+
end
129+
130+
Datadog::RubyCoreSource
131+
.create_makefile_with_core(
132+
proc do
133+
headers_available =
134+
have_header("vm_core.h") &&
135+
have_header("iseq.h") &&
136+
(RUBY_VERSION < "3.3" || have_header("ractor_core.h"))
137+
138+
if headers_available
139+
append_cflags "-Wunused-parameter"
140+
end
141+
142+
headers_available
143+
end,
144+
EXTENSION_NAME,
145+
)
146+
end
147+
148+
# rubocop:enable Style/GlobalVars
149+
# rubocop:enable Style/StderrPuts

0 commit comments

Comments
 (0)