# frozen_string_literal: true # # Copyright (c) 2016 Mark Lee and contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and # associated documentation files (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, publish, distribute, # sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all copies or # substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT # NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT # OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. require 'fileutils' require 'rbconfig' require 'thermite/semver' require 'tomlrb' module Thermite # # Configuration helper # class Config # # Creates a new configuration object. # # `options` is the same as the {Thermite::Tasks#initialize} parameter. # def initialize(options = {}) @options = options end # # Location to emit debug output, if not `nil`. Defaults to `nil`. # def debug_filename @debug_filename ||= ENV['THERMITE_DEBUG_FILENAME'] end # # The file extension of the compiled shared Rust library. # def shared_ext @shared_ext ||= if dlext == 'bundle' 'dylib' elsif Gem.win_platform? 'dll' else dlext end end # # The interpolation-formatted string used to construct the download URI for the pre-built # native extension. Can be set via the `THERMITE_BINARY_URI_FORMAT` environment variable, or a # `binary_uri_format` option. # def binary_uri_format @binary_uri_format ||= ENV['THERMITE_BINARY_URI_FORMAT'] || @options[:binary_uri_format] || false end # # The major and minor version of the Ruby interpreter that's currently running. # def ruby_version @ruby_version ||= begin version_info = rbconfig_ruby_version.split('.') "ruby#{version_info[0]}#{version_info[1]}" end end # :nocov: # # Alias for `RbConfig::CONFIG['target_cpu']`. # def target_arch @target_arch ||= RbConfig::CONFIG['target_cpu'] end # # Alias for `RbConfig::CONFIG['target_os']`. # def target_os @target_os ||= RbConfig::CONFIG['target_os'] end # :nocov: # # The name of the library compiled by Rust. # # Due to the way that Cargo works, all hyphens in library names are replaced with underscores. # def library_name @library_name ||= begin base = toml[:lib] && toml[:lib][:name] ? toml[:lib] : toml[:package] base[:name].tr('-', '_') if base[:name] end end # # The basename of the shared library built by Cargo. # def cargo_shared_library @cargo_shared_library ||= begin filename = "#{library_name}.#{shared_ext}" filename = "lib#{filename}" unless Gem.win_platform? filename end end # # The basename of the Rust shared library, as installed in the {#ruby_extension_path}. # def shared_library @shared_library ||= "#{library_name}.so" end # # Return the basename of the tarball generated by the `thermite:tarball` Rake task, given a # package `version`. # def tarball_filename(version) static = static_extension? ? '-static' : '' "#{library_name}-#{version}-#{ruby_version}-#{target_os}-#{target_arch}#{static}.tar.gz" end # # The top-level directory of the Ruby project. Defaults to the current working directory. # def ruby_toplevel_dir @ruby_toplevel_dir ||= @options.fetch(:ruby_project_path, FileUtils.pwd) end # # Generate a path relative to {#ruby_toplevel_dir}, given the `path_components` that are passed # to `File.join`. # def ruby_path(*path_components) File.join(ruby_toplevel_dir, *path_components) end # :nocov: # # Absolute path to the shared libruby. # def libruby_path @libruby_path ||= File.join(RbConfig::CONFIG['libdir'], RbConfig::CONFIG['LIBRUBY_SO']) end # :nocov: # # The top-level directory of the Cargo project. Defaults to the current working directory. # def rust_toplevel_dir @rust_toplevel_dir ||= @options.fetch(:cargo_project_path, FileUtils.pwd) end # # Generate a path relative to {#rust_toplevel_dir}, given the `path_components` that are # passed to `File.join`. # def rust_path(*path_components) File.join(rust_toplevel_dir, *path_components) end # # Generate a path relative to the `CARGO_TARGET_DIR` environment variable, or # {#rust_toplevel_dir}/target if that is not set. # def cargo_target_path(target, *path_components) target_base = ENV.fetch('CARGO_TARGET_DIR', File.join(rust_toplevel_dir, 'target')) File.join(target_base, target, *path_components) end # # If run in a multi-crate environment, the Cargo workspace member that contains the # Ruby extension. # def cargo_workspace_member @cargo_workspace_member ||= @options[:cargo_workspace_member] end # # The absolute path to the `Cargo.toml` file. The path depends on the existence of the # {#cargo_workspace_member} configuration option. # def cargo_toml_path @cargo_toml_path ||= begin components = ['Cargo.toml'] components.unshift(cargo_workspace_member) if cargo_workspace_member rust_path(*components) end end # # The relative directory where the Rust shared library resides, in the context of the Ruby # project. # def ruby_extension_dir @ruby_extension_dir ||= @options.fetch(:ruby_extension_dir, 'lib') end # # Path to the Rust shared library in the context of the Ruby project. # def ruby_extension_path ruby_path(ruby_extension_dir, shared_library) end # # The default git tag regular expression (semantic versioning format). # DEFAULT_TAG_REGEX = /^(#{Thermite::SemVer::VERSION})$/ # # The format (as a regular expression) that git tags containing Rust binary # tarballs are supposed to match. Defaults to `DEFAULT_TAG_REGEX`. # def git_tag_regex @git_tag_regex ||= if @options[:git_tag_regex] Regexp.new(@options[:git_tag_regex]) else DEFAULT_TAG_REGEX end end # # Parsed TOML object (courtesy of `tomlrb`). # def toml @toml ||= Tomlrb.load_file(cargo_toml_path, symbolize_keys: true) end # # Alias to the crate version specified in the TOML file. # def crate_version toml[:package][:version] end # # The Thermite-specific config from the TOML file. # def toml_config # Not using .dig to be Ruby < 2.3 compatible @toml_config ||= if toml && toml[:package] && toml[:package][:metadata] && toml[:package][:metadata][:thermite] toml[:package][:metadata][:thermite] else {} end end # :nocov: # # Linker flags for libruby. # def dynamic_linker_flags @dynamic_linker_flags ||= RbConfig::CONFIG['DLDFLAGS'].strip end # # Whether to use a statically linked extension. # def static_extension? ENV.key?('RUBY_STATIC') || RbConfig::CONFIG['ENABLE_SHARED'] == 'no' end private def dlext RbConfig::CONFIG['DLEXT'] end def rbconfig_ruby_version RbConfig::CONFIG['ruby_version'] end end end