ext/magic/extconf.rb (280 lines of code) (raw):
# frozen_string_literal: true
require 'find'
require 'mkmf'
require 'pathname'
LIBMAGIC_TAG = '5.39'
LIBIMAGE_SHA256 = 'f05d286a76d9556243d0cb05814929c2ecf3a5ba07963f8f70bfaaa70517fad1'
# helpful constants
PACKAGE_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
# The gem version constraint in the Rakefile is not respected at install time.
# Keep this version in sync with the one in the Rakefile !
REQUIRED_MINI_PORTILE_VERSION = "~> 2.5.0"
MAGIC_HELP_MESSAGE = <<~HELP
USAGE: ruby #{$0} [options]
Flags that are always valid:
--use-system-libraries
--enable-system-libraries
Use system libraries instead of building and using the packaged libraries.
--disable-system-libraries
Use the packaged libraries, and ignore the system libraries. This is the default on most
platforms, and overrides `--use-system-libraries` and the environment variable
`MAGIC_USE_SYSTEM_LIBRARIES`.
--disable-clean
Do not clean out intermediate files after successful build.
Flags only used when building and using the packaged libraries:
--disable-static
Do not statically link packaged libraries, instead use shared libraries.
--enable-cross-build
Enable cross-build mode. (You probably do not want to set this manually.)
Flags only used when using system libraries:
Related to libmagic:
--with-magic-dir=DIRECTORY
Look for libmagic headers and library in DIRECTORY.
--with-magic-lib=DIRECTORY
Look for libmagic library in DIRECTORY.
--with-magic-include=DIRECTORY
Look for libmagic headers in DIRECTORY.
Environment variables used:
CC
Use this path to invoke the compiler instead of `RbConfig::CONFIG['CC']`
CPPFLAGS
If this string is accepted by the C preprocessor, add it to the flags passed to the C preprocessor
CFLAGS
If this string is accepted by the compiler, add it to the flags passed to the compiler
LDFLAGS
If this string is accepted by the linker, add it to the flags passed to the linker
LIBS
Add this string to the flags passed to the linker
HELP
def process_recipe(name, version, static_p, cross_p)
require 'rubygems'
gem('mini_portile2', REQUIRED_MINI_PORTILE_VERSION)
require 'mini_portile2'
message("Using mini_portile version #{MiniPortile::VERSION}\n")
MiniPortile.new(name, version).tap do |recipe|
# Prefer host_alias over host in order to use i586-mingw32msvc as
# correct compiler prefix for cross build, but use host if not set.
recipe.host = RbConfig::CONFIG["host_alias"].empty? ? RbConfig::CONFIG["host"] : RbConfig::CONFIG["host_alias"]
recipe.target = File.join(PACKAGE_ROOT_DIR, "ports")
recipe.configure_options << "--libdir=#{File.join(recipe.path, 'lib')}"
yield recipe
env = Hash.new do |hash, key|
hash[key] = (ENV[key]).to_s
end
recipe.configure_options.flatten!
recipe.configure_options = [
"--disable-silent-rules",
"--disable-dependency-tracking",
"--enable-fsect-man5"
]
if static_p
recipe.configure_options += [
"--disable-shared",
"--enable-static",
]
env["CFLAGS"] = concat_flags(env["CFLAGS"], "-fPIC")
else
recipe.configure_options += [
"--enable-shared",
"--disable-static",
]
end
if cross_p
recipe.configure_options += [
"--target=#{recipe.host}",
"--host=#{recipe.host}",
]
end
recipe.configure_options += env.map do |key, value|
"#{key}=#{value.strip}"
end
recipe.cook
recipe.activate
end
end
#
# utility functions
#
def config_clean?
enable_config('clean', true)
end
def config_static?
default_static = !truffle?
enable_config("static", default_static)
end
def config_cross_build?
enable_config("cross-build")
end
def config_system_libraries?
enable_config("system-libraries", ENV.key?("MAGIC_USE_SYSTEM_LIBRARIES")) do |_, default|
arg_config('--use-system-libraries', default)
end
end
def darwin?
RbConfig::CONFIG['target_os'] =~ /darwin/
end
def windows?
RbConfig::CONFIG['target_os'] =~ /mswin|mingw32|windows/
end
def truffle?
::RUBY_ENGINE == 'truffleruby'
end
def concat_flags(*args)
args.compact.join(" ")
end
def do_help
print(MAGIC_HELP_MESSAGE)
exit!(0)
end
def do_clean
root = Pathname(PACKAGE_ROOT_DIR)
pwd = Pathname(Dir.pwd)
# Skip if this is a development work tree
unless (root + '.git').exist?
message("Cleaning files only used during build.\n")
# (root + 'tmp') cannot be removed at this stage because
# libmagic.so is yet to be copied to lib.
# clean the ports build directory
Pathname.glob(pwd.join('tmp', '*', 'ports')) do |dir|
FileUtils.rm_rf(dir, verbose: true)
end
FileUtils.rm_rf(root + 'ports' + 'archives', verbose: true)
# Remove everything but share/ directory
remove_paths = %w[bin include]
remove_paths << 'lib' if config_static?
Pathname.glob(File.join(root, 'ports', '*', 'libmagic', '*')) do |dir|
remove_paths.each do |path|
remove_dir = File.join(dir, path)
FileUtils.rm_rf(remove_dir, verbose: true)
end
end
end
exit!(0)
end
#
# main
#
do_help if arg_config('--help')
do_clean if arg_config('--clean')
if ENV['CC']
RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC']
end
ENV['CC'] = RbConfig::CONFIG['CC']
append_cflags(ENV["CFLAGS"].split) if ENV["CFLAGS"]
append_cppflags(ENV["CPPFLAGS"].split) if ENV["CPPFLAGS"]
append_ldflags(ENV["LDFLAGS"].split) if ENV["LDFLAGS"]
$LIBS = concat_flags($LIBS, ENV["LIBS"]) if ENV["LIBS"]
if config_system_libraries?
message "Building ruby-magic using system libraries.\n"
$CPPFLAGS += " -DMAGIC_SYSTEM_LIBRARIES"
dir_config('magic')
else
message "Building ruby-magic using packaged libraries.\n"
static_p = config_static?
message "Static linking is #{static_p ? 'enabled' : 'disabled'}.\n"
cross_build_p = config_cross_build?
message "Cross build is #{cross_build_p ? 'enabled' : 'disabled'}.\n"
libmagic_recipe = process_recipe('libmagic', LIBMAGIC_TAG, static_p, cross_build_p) do |recipe|
recipe.files = [{
url: "https://gitlab.com/gitlab-org/file-mirror/-/package_files/8589820/download",
sha256: LIBIMAGE_SHA256
}]
end
$LIBPATH = [File.join(libmagic_recipe.path, 'lib')]
$CFLAGS << " -I#{File.join(libmagic_recipe.path, 'include')} "
$LDFLAGS += " -Wl,-rpath,#{libmagic_recipe.path}/lib"
if static_p
ENV['PKG_CONFIG_PATH'] = "#{libmagic_recipe.path}/lib/pkgconfig"
# mkmf appends -- to the first option
$LIBS += " " + pkg_config('libmagic', 'libs --static')
$LIBS += " " + File.join(libmagic_recipe.path, 'lib', "libmagic.#{$LIBEXT}")
end
end
$CFLAGS += ' -std=c99'
if RbConfig::CONFIG['CC'] =~ /gcc/
$CFLAGS += ' -O3' unless $CFLAGS =~ /-O\d/
end
%w[
-Wcast-qual
-Wwrite-strings
-Wconversion
-Wmissing-noreturn
-Winline
].select do |flag|
try_link('int main(void) { return 0; }', flag)
end.each do |flag|
$CFLAGS += " " + flag
end
unless darwin?
$LDFLAGS += ' -Wl,--as-needed -Wl,--exclude-libs,ALL'
end
if windows?
$LDFLAGS += ' -static-libgcc'
end
unless have_header('ruby.h')
abort "\n" + (<<-EOS).gsub(/^[ ]{,3}/, '') + "\n"
You appear to be missing Ruby development libraries and/or header
files. You can install missing compile-time dependencies in one of
the following ways:
- Debian / Ubuntu
apt-get install ruby-dev
- Red Hat / CentOS / Fedora
yum install ruby-devel or dnf install ruby-devel
- Mac OS X (Darwin)
brew install ruby (for Homebrew, see https://brew.sh)
port install ruby2.6 (for MacPorts, see https://www.macports.org)
- OpenBSD / NetBSD
pkg_add ruby (for pkgsrc, see https://www.pkgsrc.org)
- FreeBSD
pkg install ruby (for FreeBSD Ports, see https://www.freebsd.org/ports)
Alternatively, you can use either of the following Ruby version
managers in order to install Ruby locally (for your user only)
and/or system-wide:
- Ruby Version Manager (for RVM, see https://rvm.io)
- Ruby Environment (for rbenv, see https://github.com/sstephenson/rbenv)
- Change Ruby (for chruby, see https://github.com/postmodern/chruby)
More information about how to install Ruby on various platforms
available at the following web site:
https://www.ruby-lang.org/en/documentation/installation
EOS
end
have_func('rb_thread_call_without_gvl')
have_func('rb_thread_blocking_region')
unless have_header('magic.h')
abort "\n" + (<<-EOS).gsub(/^[ ]{,3}/, '') + "\n"
You appear to be missing libmagic(3) library and/or necessary header
files. You can install missing compile-time dependencies in one of
the following ways:
- Debian / Ubuntu
apt-get install libmagic-dev
- Red Hat / CentOS / Fedora
yum install file-devel or dns install file-devel
- Mac OS X (Darwin)
brew install libmagic (for Homebrew, see https://brew.sh)
port install libmagic (for MacPorts, see https://www.macports.org)
- OpenBSD / NetBSD
pkg_add file (for pkgsrc, see https://www.pkgsrc.org)
- FreeBSD
pkg install file (for FreeBSD Ports, see https://www.freebsd.org/ports)
Alternatively, you can download recent release of the file(1) package
from the following web site and attempt to compile libmagic(3) manually:
https://www.darwinsys.com/file
EOS
end
have_library('magic')
unless have_func('magic_getpath')
abort "\n" + (<<-EOS).gsub(/^[ ]{,3}/, '') + "\n"
Your version of libmagic(3) appears to be too old.
Please, consider upgrading to at least version 5.29 or newer,
if possible. For more information about file(1) command and
libmagic(3) please visit the following web site:
https://www.darwinsys.com/file
EOS
end
have_func('magic_getflags')
%w[
utime.h
sys/types.h
sys/time.h
].each do |h|
have_header(h)
end
%w[
utime
utimes
].each do |f|
have_func(f)
end
create_header
create_makefile('magic/magic')
if config_clean?
# Do not clean if run in a development work tree.
File.open('Makefile', 'at') do |mk|
mk.print(<<~EOF)
all: clean-ports
clean-ports: $(DLLIB)
\t-$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? 'enable' : 'disable'}-static
EOF
end
end