From ac14e8f9af0632f18fe12c568795cc9a9bcd6a7f Mon Sep 17 00:00:00 2001 From: Paul Mucur Date: Fri, 22 Mar 2024 14:42:14 +0000 Subject: [PATCH] Re-implement parts of mkmf_config As MiniPortile2's mkmf_config doesn't quite work for our use case yet, refactor to combine its approach with our previous one: stop using MiniPortile#activate to populate the required compiler and linker options and instead set them ourselves based on the output of pkg-config. The key things we're trying to replace are as follows: * Populating $CPPFLAGS and $LIBPATH with dir_config * Populating $libs, $INCFLAGS, $LDFLAGS, $CFLAGS and $CXXFLAGS with pkg_config Instead, we only set the following: * $LIBPATH with the paths reported by pkg-config --libs-only-L * $libs with all libraries, replacing them with static absolute paths where possible * $INCFLAGS as reported by pkg-config --cflags-only-I * $CFLAGS and $CXXFLAGS as reported by pkg-config --cflags-only-other --- ext/re2/extconf.rb | 67 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/ext/re2/extconf.rb b/ext/re2/extconf.rb index 56838f8..5ef140f 100644 --- a/ext/re2/extconf.rb +++ b/ext/re2/extconf.rb @@ -99,30 +99,60 @@ def build_with_vendored_libraries abseil_recipe, re2_recipe = load_recipes + # Compile Abseil process_recipe(abseil_recipe) do |recipe| recipe.configure_options += ['-DABSL_PROPAGATE_CXX_STD=ON', '-DCMAKE_CXX_VISIBILITY_PRESET=hidden'] # Workaround for https://github.com/abseil/abseil-cpp/issues/1510 recipe.configure_options += ['-DCMAKE_CXX_FLAGS=-DABSL_FORCE_WAITER_MODE=4'] if windows? end - abseil_recipe.activate - + # Compile RE2 process_recipe(re2_recipe) do |recipe| + # Specify Abseil's path so RE2 will prefer that over any system Abseil recipe.configure_options += ["-DCMAKE_PREFIX_PATH=#{abseil_recipe.path}", '-DCMAKE_CXX_FLAGS=-DNDEBUG', '-DCMAKE_CXX_VISIBILITY_PRESET=hidden'] end - dir_config("re2", File.join(re2_recipe.path, 'include'), File.join(re2_recipe.path, 'lib')) - dir_config("abseil", File.join(abseil_recipe.path, 'include'), File.join(abseil_recipe.path, 'lib')) + # on macOS, pkg-config will not return --cflags without this + ENV["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "t" + ENV["PKG_CONFIG_PATH"] = [ + "#{abseil_recipe.lib_path}/pkgconfig", + "#{re2_recipe.lib_path}/pkgconfig", + ENV["PKG_CONFIG_PATH"] + ].compact.join(File::PATH_SEPARATOR) - pkg_config_paths = [ - "#{abseil_recipe.path}/lib/pkgconfig", - "#{re2_recipe.path}/lib/pkgconfig" - ] - pkg_config_paths.prepend(ENV['PKG_CONFIG_PATH']) if ENV['PKG_CONFIG_PATH'] - ENV['PKG_CONFIG_PATH'] = pkg_config_paths.join(File::PATH_SEPARATOR) + pc_file = File.join(re2_recipe.lib_path, 'pkgconfig', 're2.pc') + + static_library_dirs = minimal_pkg_config(pc_file, '--libs-only-L', '--static') + .shellsplit + .map { |flag| flag.sub(/\A-L/, "") } + + $LIBPATH = static_library_dirs | $LIBPATH + + # Replace all -l flags that can be found in one of the static library + # directories with the full path instead. + libflags = minimal_pkg_config(pc_file, '--libs-only-l', '--static') + .shellsplit + .map do |flag| + next flag unless flag.start_with?("-l") + + static_lib = "lib#{flag[2..]}.#{$LIBEXT}" + static_lib_dir = static_library_dirs.find { |dir| File.exist?(File.join(dir, static_lib)) } + next flag unless static_lib_dir + + File.join(static_lib_dir, static_lib) + end - re2_recipe.mkmf_config(pkg: 're2', static: 're2') + $libs = [libflags, $libs].join(" ").strip + + # Prepend INCFLAGS + incflags = minimal_pkg_config(pc_file, '--cflags-only-I') + $INCFLAGS = [incflags, $INCFLAGS].join(" ").strip + + # Append CFLAGS and CXXFLAGS + cflags = minimal_pkg_config(pc_file, '--cflags-only-other') + $CFLAGS = [$CFLAGS, cflags].join(" ").strip + $CXXFLAGS = [$CXXFLAGS, cflags].join(" ").strip end def build_extension @@ -251,6 +281,21 @@ def process_recipe(recipe) end end + def minimal_pkg_config(pc_file, *options) + if ($PKGCONFIG ||= + (pkgconfig = MakeMakefile.with_config("pkg-config") {MakeMakefile.config_string("PKG_CONFIG") || "pkg-config"}) && + MakeMakefile.find_executable0(pkgconfig) && pkgconfig) + pkgconfig = $PKGCONFIG + else + raise RuntimeError, "pkg-config is not found" + end + + response = xpopen([pkgconfig, *options, pc_file], err: %i[child out], &:read) + raise RuntimeError, response unless $?.success? + + response.strip + end + def config_system_libraries? enable_config("system-libraries", ENV.key?('RE2_USE_SYSTEM_LIBRARIES')) end