# Copyright (c) 2023 M.J.N. Corino, The Netherlands # # This software is released under the MIT license. ### # wxRuby3 buildtools configuration ### require 'set' module WXRuby3 module Config # Common code for platforms that use wx-config (basically, everything # not MSW) module UnixLike def check_wx_config !expand("which #{@wx_config} 2>/dev/null").chomp.empty? end # Helper function that runs the wx-config command line program from # wxWidgets to determine suitable builds and build options. Passed an # option which corresponds to one of the command-line options to # wx-config, eg '--list' or '--libs'. See --help for that program. def wx_config(option) # if @release_build debug_mode = '--debug=no' elsif @debug_build debug_mode = '--debug=yes' end cfg = expand("#{@wx_config} #{debug_mode} --static=no #{option} 2>&1") # Check status for errors unless $?.exitstatus.zero? if cfg =~ /Warning: No config found to match:([^\n]*)/ STDERR.puts "ERROR: No suitable wxWidgets found for specified build options " + "(#{$1.strip})" else STDERR.puts "ERROR: wx-config error (#{cfg})" end exit(1) end return cfg.strip end def do_link(pkg) objs = pkg.all_obj_files.collect { |o| File.join('..', o) }.join(' ') + ' ' depsh = pkg.dep_libnames.collect { |dl| "#{dl}.#{dll_ext}" }.join(' ') sh "cd lib && #{WXRuby3.config.ld} #{WXRuby3.config.ldflags(pkg.lib_target)} #{objs} #{depsh} " + "#{WXRuby3.config.libs} #{WXRuby3.config.link_output_flag}#{pkg.lib_target}", fail_on_error: true end def check_tool_pkgs pkg_deps = super pkg_deps << 'doxygen' unless system('command -v doxygen>/dev/null') pkg_deps << 'swig' unless system('command -v swig>/dev/null') pkg_deps end def get_rpath_origin "$ORIGIN" end protected :get_rpath_origin # add deployment lookup paths for wxruby shared libraries def update_shlib_loadpaths(shlib) WXRuby3.config.patch_rpath(shlib, WXRuby3.config.get_rpath_origin, "#{WXRuby3.config.get_rpath_origin}/../ext") end def expand(cmd) STDERR.puts "> sh: #{cmd}" if verbose? s = super STDERR.puts "< #{s}" if verbose? s end def download_file(url, dest) sh("curl -L #{url} --output #{dest}") end private def wx_checkout $stdout.print 'Checking out wxWidgets...' if run_silent? # clone wxWidgets GIT repository under ext_path chdir(ext_path) do if (rc = sh("#{get_cfg_string('git')} clone https://github.com/wxWidgets/wxWidgets.git")) chdir('wxWidgets') do tag = wx_gitref || expand("#{get_cfg_string('git')} tag").split("\n").select do |t| (/\Av(\d+)\.(\d+)\.\d+\Z/ =~ t) && (($1.to_i == 3 && $2.to_i >= 2) || $1.to_i > 3) end.max # checkout the version we are building against rc = sh("#{get_cfg_string('git')} checkout #{tag}") end end if rc $stdout.puts 'done!' if run_silent? else $stderr.puts "ERROR: Failed to checkout wxWidgets." exit(1) end end end def wx_configure bash('./configure --prefix=`pwd`/install --disable-tests --without-subdirs --without-regex --disable-debug_info') end def wx_make bash('make -j$(nproc) && make install') end def wx_build $stdout.print 'Configuring wxWidgets...' if run_silent? # initialize submodules unless sh("#{get_cfg_string('git')} submodule update --init") $stderr.puts "ERROR: Failed to update wxWidgets submodules." exit(1) end # configure wxWidgets unless wx_configure $stderr.puts "ERROR: Failed to configure wxWidgets." exit(1) end $stdout.puts 'done!' if run_silent? $stdout.print 'Building wxWidgets...' if run_silent? # make and install wxWidgets unless wx_make $stderr.puts "ERROR: Failed to build wxWidgets libraries." exit(1) end $stdout.puts 'done!' if run_silent? end def wx_generate_xml chdir(File.join(ext_path, 'wxWidgets', 'docs', 'doxygen')) do unless sh({ 'DOXYGEN' => get_cfg_string("doxygen"), 'WX_SKIP_DOXYGEN_VERSION_CHECK' => '1' }, './regen.sh xml') $stderr.puts 'ERROR: Failed to generate wxWidgets XML API specifications for parsing by wxRuby3.' exit(1) end end end # Allow specification of custom wxWidgets build (mostly useful for # static wxRuby3 builds) def get_wx_path get_config('with-wxwin') && get_cfg_string('wxwin').empty? ? File.join(ext_path, 'wxWidgets', 'install') : get_cfg_string('wxwin') end def get_wx_xml_path get_cfg_string('wxxml') end def get_wx_libs wx_libset = ::Set.new wx_libset.merge wx_config("--libs all").split(' ') # some weird thing with this; at least sometimes '--libs all' will not output media library even if feature active if features_set?('USE_MEDIACTRL') wx_libset.merge wx_config("--libs media").split(' ') end wx_libset.collect { |s| s.dup } end def init_unix_platform # Allow specification of custom wxWidgets build (mostly useful for # static wxRuby3 builds) @wx_path = get_wx_path STDERR.puts "> wx_path = '#{@wx_path}'" if verbose? @wx_xml_path = get_wx_xml_path @wx_config = @wx_path.empty? ? 'wx-config' : File.join(@wx_path, 'bin', 'wx-config') if check_wx_config # Now actually run the program to fill in some variables @wx_version = wx_config('--version') @wx_port = case wx_config('--selected-config') when /\Agtk/ :wxgtk when /\Aqt/ :wxqt when /\Ax11/ :wxx11 when /\Amotif/ :wxmotif when /\Amsw/ :wxmsw when /\Aosx/ :wxosx else nil end @wx_cppflags = wx_config('--cppflags').split(' ') # Find out where the wxWidgets setup.h file being used is located setup_inc_dir = @wx_cppflags.find { |flag| flag =~ /^-I\S+/ }[2..-1] @wx_setup_h = File.join(setup_inc_dir, 'wx', 'setup.h') @cpp = wx_config("--cxx") @ld = wx_config("--ld") @wx_libs = get_wx_libs # remove all warning flags provided by Ruby config @ruby_cppflags = @ruby_cppflags.collect { |flags| flags.split(' ') }.flatten. select { |o| !o.start_with?('-W') || o.start_with?('-Wl,') } @ruby_cppflags.concat %w[-Wall -Wextra -Wno-unused-parameter] # only keep these # add include flags @ruby_cppflags.concat ['-I.', *@ruby_includes.collect { |inc| "-I#{inc}" }] @ruby_ldflags << "-Wl,-rpath,'#{get_rpath_origin}/../lib'" # add default rpath @ruby_libs << "-L#{RB_CONFIG['libdir']}" # add ruby lib dir # add ruby defined shared ruby lib(s); not any other flags @ruby_libs.concat RB_CONFIG['LIBRUBYARG_SHARED'].split(' ').select { |s| s.start_with?('-l')} end end end end end