Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ext/datadog_profiling_native_extension/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def skip_building_extension!(reason)
# that may fail on an environment not properly setup for building Ruby extensions.
require "mkmf"

Datadog::LibdatadogExtconfHelpers.add_shared_sources!(
extension_dir: __dir__,
shared_relative_dir: File.join("..", "shared")
)

Logging.message("[datadog] Using compiler:\n")
xsystem("#{CONFIG["CC"]} -v")
Logging.message("[datadog] End of compiler information\n")
Expand Down
80 changes: 0 additions & 80 deletions ext/libdatadog_api/datadog_ruby_common.c

This file was deleted.

63 changes: 0 additions & 63 deletions ext/libdatadog_api/datadog_ruby_common.h

This file was deleted.

5 changes: 5 additions & 0 deletions ext/libdatadog_api/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ def skip_building_extension!(reason)

require 'mkmf'

Datadog::LibdatadogExtconfHelpers.add_shared_sources!(
extension_dir: __dir__,
shared_relative_dir: File.join('..', 'shared')
)

# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
append_cflags '-Werror' if ENV['DATADOG_GEM_CI'] == 'true'
Expand Down
20 changes: 20 additions & 0 deletions ext/libdatadog_extconf_helpers.rb
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw if you want to add any specs (hint hint lol haha), there's already a libdatadog_extconf_helpers_spec.rb living inside profiling that we can use ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the other comments, you brought up very good concerns that I didn't think of when writing this.
So I'll see if I can get as many of them as possible in tests, thank you so much for all the feedback!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! TBH I think this is already in very good shape so feel free to split improvements into separate PRs vs waiting for a bigger PR with it all ;)

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ module LibdatadogExtconfHelpers
# may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
LIBDATADOG_VERSION = '~> 24.0.1.1.0'

# Include sources in the `shared` directory. We intentionally:
# * Keep every entry in $srcs to the basename so mkmf/VPATH can resolve them correctly.
# * Add the shared directory to $VPATH using $(srcdir) so the generated Makefile works no matter where it's run from.
# * Extend $INCFLAGS with the same path so headers resolve without absolute paths that would break relocation.
def self.add_shared_sources!(extension_dir:, shared_relative_dir:)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Maybe hardcode shared_relative_dir? I think for now it's easier to keep shared stuff together and we can always reintroduce this later.

shared_absolute_dir = File.expand_path(shared_relative_dir, extension_dir)
shared_sources = Dir[File.join(shared_absolute_dir, '*.c')].map { |path| File.basename(path) }
extension_sources = Dir[File.join(extension_dir, '*.c')].map { |path| File.basename(path) }

$srcs = extension_sources + shared_sources
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I added this to the bottom of the extconf.rb so I could compare between master and this branch:

$stderr.puts("$srcs: #{$srcs.inspect}")
$stderr.puts("$VPATH: #{$objs.inspect}")
$stderr.puts("$INCFLAGS: #{$INCFLAGS.inspect}")

and I got this on master:

$srcs: ["../../../../ext/datadog_profiling_native_extension/clock_id_from_pthread.c", "../../../../ext/datadog_profiling_native_extension/clock_id_noop.c", "../../../../ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c", "../../../../ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c", "../../../../ext/datadog_profiling_native_extension/collectors_dynamic_sampling_rate.c", "../../../../ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c", "../../../../ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c", "../../../../ext/datadog_profiling_native_extension/collectors_stack.c", "../../../../ext/datadog_profiling_native_extension/collectors_thread_context.c", "../../../../ext/datadog_profiling_native_extension/datadog_ruby_common.c", "../../../../ext/datadog_profiling_native_extension/encoded_profile.c", "../../../../ext/datadog_profiling_native_extension/gvl_profiling_helper.c", "../../../../ext/datadog_profiling_native_extension/heap_recorder.c", "../../../../ext/datadog_profiling_native_extension/http_transport.c", "../../../../ext/datadog_profiling_native_extension/libdatadog_helpers.c", "../../../../ext/datadog_profiling_native_extension/private_vm_api_access.c", "../../../../ext/datadog_profiling_native_extension/profiling.c", "../../../../ext/datadog_profiling_native_extension/ruby_helpers.c", "../../../../ext/datadog_profiling_native_extension/setup_signal_handler.c", "../../../../ext/datadog_profiling_native_extension/stack_recorder.c", "../../../../ext/datadog_profiling_native_extension/time_helpers.c", "../../../../ext/datadog_profiling_native_extension/unsafe_api_calls_check.c"]
$VPATH: ["clock_id_from_pthread.o", "clock_id_noop.o", "collectors_cpu_and_wall_time_worker.o", "collectors_discrete_dynamic_sampler.o", "collectors_dynamic_sampling_rate.o", "collectors_gc_profiling_helper.o", "collectors_idle_sampling_helper.o", "collectors_stack.o", "collectors_thread_context.o", "datadog_ruby_common.o", "encoded_profile.o", "gvl_profiling_helper.o", "heap_recorder.o", "http_transport.o", "libdatadog_helpers.o", "private_vm_api_access.o", "profiling.o", "ruby_helpers.o", "setup_signal_handler.o", "stack_recorder.o", "time_helpers.o", "unsafe_api_calls_check.o"]
$INCFLAGS: "-I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -I/home/ivo.anjo/.rvm/gems/ruby-3.4.7/gems/libdatadog-24.0.1.1.0-x86_64-linux/vendor/libdatadog-24.0.1/x86_64-linux/libdatadog-x86_64-unknown-linux-gnu/lib/pkgconfig/../../include"

...and this on this branch:

$srcs: ["clock_id_from_pthread.c", "clock_id_noop.c", "collectors_cpu_and_wall_time_worker.c", "collectors_discrete_dynamic_sampler.c", "collectors_dynamic_sampling_rate.c", "collectors_gc_profiling_helper.c", "collectors_idle_sampling_helper.c", "collectors_stack.c", "collectors_thread_context.c", "encoded_profile.c", "gvl_profiling_helper.c", "heap_recorder.c", "http_transport.c", "libdatadog_helpers.c", "private_vm_api_access.c", "profiling.c", "ruby_helpers.c", "setup_signal_handler.c", "stack_recorder.c", "time_helpers.c", "unsafe_api_calls_check.c", "datadog_ruby_common.c"]
$VPATH: ["clock_id_from_pthread.o", "clock_id_noop.o", "collectors_cpu_and_wall_time_worker.o", "collectors_discrete_dynamic_sampler.o", "collectors_dynamic_sampling_rate.o", "collectors_gc_profiling_helper.o", "collectors_idle_sampling_helper.o", "collectors_stack.o", "collectors_thread_context.o", "encoded_profile.o", "gvl_profiling_helper.o", "heap_recorder.o", "http_transport.o", "libdatadog_helpers.o", "private_vm_api_access.o", "profiling.o", "ruby_helpers.o", "setup_signal_handler.o", "stack_recorder.o", "time_helpers.o", "unsafe_api_calls_check.o", "datadog_ruby_common.o"]
$INCFLAGS: "-I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -I$(srcdir)/../shared -I/home/ivo.anjo/.rvm/gems/ruby-3.4.7/gems/libdatadog-24.0.1.1.0-x86_64-linux/vendor/libdatadog-24.0.1/x86_64-linux/libdatadog-x86_64-unknown-linux-gnu/lib/pkgconfig/../../include"

I usually avoid the vague "let's do X 'just in case'" approach to things, but given:

  • We need to support many Ruby versions and there's many different ways of setting stuff up
  • It's easy to match exactly what Ruby does

My suggestion would be to setup $srcs exactly like Ruby does (e.g. with the relative paths from the RbConfig srcdir). I don't have a "oh this won't work like this reason", it's 100% just in case 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add some extra documentation for this section, regarding the pattern of following the upstream pattern.
I'll take a look too at a few other popular gems to see how they do it, and I'll document if I find anything interesting.

$VPATH ||= []

shared_search_dir = File.join('$(srcdir)', shared_relative_dir)
$VPATH << shared_search_dir unless $VPATH.include?(shared_search_dir)

$INCFLAGS ||= ''
include_token = " -I#{shared_search_dir}"
$INCFLAGS << include_token unless $INCFLAGS.include?(include_token)
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I soft-suspected we may be missing something with the headers, since if we don't explicitly list all headers in the Makefile, make won't know to rebuild the code if the header changes (even though it can find the headers).

I diff'd the Makefile that gets generated before and after this change and noticed that indeed this was the case:

-HDRS = $(srcdir)/clock_id.h $(srcdir)/collectors_discrete_dynamic_sampler.h $(srcdir)/collectors_dynamic_sampling_rate.h $(srcdir)/collectors_gc_profiling_helper.h $(srcdir)/collectors_idle_sampling_helper.h $(srcdir)/collectors_stack.h $(srcdir)/collectors_thread_context.h $(srcdir)/datadog_ruby_common.h $(srcdir)/encoded_profile.h $(srcdir)/gvl_profiling_helper.h $(srcdir)/heap_recorder.h $(srcdir)/helpers.h $(srcdir)/libdatadog_helpers.h $(srcdir)/private_vm_api_access.h $(srcdir)/ruby_helpers.h $(srcdir)/setup_signal_handler.h $(srcdir)/stack_recorder.h $(srcdir)/time_helpers.h $(srcdir)/unsafe_api_calls_check.h
+HDRS = $(srcdir)/clock_id.h $(srcdir)/collectors_discrete_dynamic_sampler.h $(srcdir)/collectors_dynamic_sampling_rate.h $(srcdir)/collectors_gc_profiling_helper.h $(srcdir)/collectors_idle_sampling_helper.h $(srcdir)/collectors_stack.h $(srcdir)/collectors_thread_context.h $(srcdir)/encoded_profile.h $(srcdir)/gvl_profiling_helper.h $(srcdir)/heap_recorder.h $(srcdir)/helpers.h $(srcdir)/libdatadog_helpers.h $(srcdir)/private_vm_api_access.h $(srcdir)/ruby_helpers.h $(srcdir)/setup_signal_handler.h $(srcdir)/stack_recorder.h $(srcdir)/time_helpers.h $(srcdir)/unsafe_api_calls_check.h

TL;DR I believe $headers is the correct thing to add to so the headers get added to the Makefile as well (I think they end up in a different definition, not HDRS, but it should be equivalent, and running bundle exec rake compile after changing only the header should trigger a rebuild)


# Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
# libdatadog are moved after the extension gets compiled.
#
Expand Down
17 changes: 0 additions & 17 deletions spec/datadog/core/datadog_ruby_common_spec.rb

This file was deleted.

Loading