diff --git a/README.md b/README.md index f2d0df8..7757a67 100644 --- a/README.md +++ b/README.md @@ -85,22 +85,29 @@ system-wide installation. Some keyword arguments can be passed to the constructor to configure the commands used: -#### `cc_command` +#### `cc_command` and `cxx_command` -The compiler command that is used is configurable, and in order of preference will use: +The C compiler command that is used is configurable, and in order of preference will use: - the `CC` environment variable (if present) - the `:cc_command` keyword argument passed in to the constructor - `RbConfig::CONFIG["CC"]` - `"gcc"` -You can pass it in like so: +The C++ compiler is similarly configuratble, and in order of preference will use: + +- the `CXX` environment variable (if present) +- the `:cxx_command` keyword argument passed in to the constructor +- `RbConfig::CONFIG["CXX"]` +- `"g++"` + +You can pass your compiler commands to the MiniPortile constructor: ``` ruby -MiniPortile.new("libiconv", "1.13.1", cc_command: "cc") +MiniPortile.new("libiconv", "1.13.1", cc_command: "clang", cxx_command: "clang++") ``` -For backwards compatibility, the constructor also supports a keyword argument `:gcc_command`. +(For backwards compatibility, the constructor also supports a keyword argument `:gcc_command` for the C compiler.) #### `make_command` diff --git a/lib/mini_portile2/mini_portile.rb b/lib/mini_portile2/mini_portile.rb index 72df973..deb2c8c 100644 --- a/lib/mini_portile2/mini_portile.rb +++ b/lib/mini_portile2/mini_portile.rb @@ -107,6 +107,7 @@ def initialize(name, version, **kwargs) @source_directory = nil @cc_command = kwargs[:cc_command] || kwargs[:gcc_command] + @cxx_command = kwargs[:cxx_command] @make_command = kwargs[:make_command] @open_timeout = kwargs[:open_timeout] || DEFAULT_TIMEOUT @read_timeout = kwargs[:read_timeout] || DEFAULT_TIMEOUT @@ -377,6 +378,10 @@ def cc_cmd end alias :gcc_cmd :cc_cmd + def cxx_cmd + (ENV["CXX"] || @cxx_command || RbConfig::CONFIG["CXX"] || "g++").dup + end + def make_cmd (ENV["MAKE"] || @make_command || ENV["make"] || "make").dup end diff --git a/lib/mini_portile2/mini_portile_cmake.rb b/lib/mini_portile2/mini_portile_cmake.rb index 9fcfb4c..da834cc 100644 --- a/lib/mini_portile2/mini_portile_cmake.rb +++ b/lib/mini_portile2/mini_portile_cmake.rb @@ -67,49 +67,21 @@ def generator_defaults end def cmake_compile_flags - c_compiler, cxx_compiler = find_c_and_cxx_compilers(host) + # RbConfig::CONFIG['CC'] and RbConfig::CONFIG['CXX'] can contain additional flags, for example + # "clang++ -std=gnu++11" or "clang -fdeclspec". CMake is just looking for the command name. + cc_compiler = cc_cmd.split.first + cxx_compiler = cxx_cmd.split.first # needed to ensure cross-compilation with CMake targets the right CPU and compilers [ "-DCMAKE_SYSTEM_NAME=#{cmake_system_name}", "-DCMAKE_SYSTEM_PROCESSOR=#{cpu_type}", - "-DCMAKE_C_COMPILER=#{c_compiler}", + "-DCMAKE_C_COMPILER=#{cc_compiler}", "-DCMAKE_CXX_COMPILER=#{cxx_compiler}", "-DCMAKE_BUILD_TYPE=#{cmake_build_type}", ] end - def find_compiler(compilers) - compilers.find { |binary| which(binary) } - end - - # configure automatically searches for the right compiler based on the - # `--host` parameter. However, CMake doesn't have an equivalent feature. - # Search for the right compiler for the target architecture using - # some basic heruistics. - def find_c_and_cxx_compilers(host) - c_compiler = ENV["CC"] - cxx_compiler = ENV["CXX"] - - if MiniPortile.darwin? - c_compiler ||= 'clang' - cxx_compiler ||='clang++' - elsif MiniPortile.freebsd? - c_compiler ||= 'cc' - cxx_compiler ||= 'c++' - else - c_compiler ||= 'gcc' - cxx_compiler ||= 'g++' - end - - c_platform_compiler = "#{host}-#{c_compiler}" - cxx_platform_compiler = "#{host}-#{cxx_compiler}" - c_compiler = find_compiler([c_platform_compiler, c_compiler]) - cxx_compiler = find_compiler([cxx_platform_compiler, cxx_compiler]) - - [c_compiler, cxx_compiler] - end - # Full list: https://gitlab.kitware.com/cmake/cmake/-/blob/v3.26.4/Modules/CMakeDetermineSystem.cmake?ref_type=tags#L12-31 def cmake_system_name return system_name if system_name diff --git a/test/test_cmake.rb b/test/test_cmake.rb index 6d5ffa0..e180877 100644 --- a/test/test_cmake.rb +++ b/test/test_cmake.rb @@ -83,23 +83,20 @@ def test_make_command_configuration end def test_configure_defaults_with_macos - recipe = init_recipe - recipe.host = 'some-host' - with_env({ "CC" => nil, "CXX" => nil }) do MiniPortile.stub(:darwin?, true) do with_stubbed_target(os: 'darwin22', cpu: 'arm64') do - with_compilers(recipe, host_prefix: true, c_compiler: 'clang', cxx_compiler: 'clang++') do + with_compilers(c_compiler: 'clang', cxx_compiler: 'clang++') do Open3.stub(:capture2, cmake_help_mock('Unix')) do assert_equal( [ "-DCMAKE_SYSTEM_NAME=Darwin", "-DCMAKE_SYSTEM_PROCESSOR=arm64", - "-DCMAKE_C_COMPILER=some-host-clang", - "-DCMAKE_CXX_COMPILER=some-host-clang++", + "-DCMAKE_C_COMPILER=clang", + "-DCMAKE_CXX_COMPILER=clang++", "-DCMAKE_BUILD_TYPE=Release" ], - recipe.configure_defaults) + @recipe.configure_defaults) end end end @@ -108,12 +105,9 @@ def test_configure_defaults_with_macos end def test_configure_defaults_with_freebsd - recipe = init_recipe - recipe.host = 'some-host' - with_env({ "CC" => nil, "CXX" => nil }) do with_stubbed_target(os: 'freebsd14') do - with_compilers(recipe, c_compiler: 'cc', cxx_compiler: 'c++') do + with_compilers(c_compiler: 'cc', cxx_compiler: 'c++') do Open3.stub(:capture2, cmake_help_mock('Unix')) do assert_equal( [ @@ -123,7 +117,7 @@ def test_configure_defaults_with_freebsd "-DCMAKE_CXX_COMPILER=c++", "-DCMAKE_BUILD_TYPE=Release" ], - recipe.configure_defaults) + @recipe.configure_defaults) end end end @@ -131,22 +125,21 @@ def test_configure_defaults_with_freebsd end def test_configure_defaults_with_manual_system_name - recipe = init_recipe - recipe.system_name = 'Custom' - MiniPortile.stub(:darwin?, false) do with_stubbed_target do - with_compilers(recipe) do + with_compilers do Open3.stub(:capture2, cmake_help_mock('Unix')) do - assert_equal( - [ - "-DCMAKE_SYSTEM_NAME=Custom", - "-DCMAKE_SYSTEM_PROCESSOR=x86_64", - "-DCMAKE_C_COMPILER=gcc", - "-DCMAKE_CXX_COMPILER=g++", - "-DCMAKE_BUILD_TYPE=Release" - ], - recipe.configure_defaults) + @recipe.stub(:system_name, 'Custom') do + assert_equal( + [ + "-DCMAKE_SYSTEM_NAME=Custom", + "-DCMAKE_SYSTEM_PROCESSOR=x86_64", + "-DCMAKE_C_COMPILER=gcc", + "-DCMAKE_CXX_COMPILER=g++", + "-DCMAKE_BUILD_TYPE=Release" + ], + @recipe.configure_defaults) + end end end end @@ -154,16 +147,14 @@ def test_configure_defaults_with_manual_system_name end def test_configure_defaults_with_unix_makefiles - recipe = init_recipe - MiniPortile.stub(:linux?, true) do MiniPortile.stub(:darwin?, false) do with_stubbed_target do - with_compilers(recipe) do + with_compilers do Open3.stub(:capture2, cmake_help_mock('Unix')) do MiniPortile.stub(:mingw?, true) do assert_equal(default_x86_compile_flags, - recipe.configure_defaults) + @recipe.configure_defaults) end end end @@ -173,15 +164,13 @@ def test_configure_defaults_with_unix_makefiles end def test_configure_defaults_with_msys_makefiles - recipe = init_recipe - MiniPortile.stub(:linux?, true) do MiniPortile.stub(:darwin?, false) do with_stubbed_target do - with_compilers(recipe) do + with_compilers do Open3.stub(:capture2, cmake_help_mock('MSYS')) do MiniPortile.stub(:mingw?, true) do - assert_equal(['-G', 'MSYS Makefiles'] + default_x86_compile_flags, recipe.configure_defaults) + assert_equal(['-G', 'MSYS Makefiles'] + default_x86_compile_flags, @recipe.configure_defaults) end end end @@ -191,15 +180,13 @@ def test_configure_defaults_with_msys_makefiles end def test_configure_defaults_with_nmake_makefiles - recipe = init_recipe - MiniPortile.stub(:linux?, true) do MiniPortile.stub(:darwin?, false) do with_stubbed_target do - with_compilers(recipe) do + with_compilers do Open3.stub(:capture2, cmake_help_mock('NMake')) do MiniPortile.stub(:mswin?, true) do - assert_equal(['-G', 'NMake Makefiles'] + default_x86_compile_flags, recipe.configure_defaults) + assert_equal(['-G', 'NMake Makefiles'] + default_x86_compile_flags, @recipe.configure_defaults) end end end @@ -240,21 +227,11 @@ def with_stubbed_target(os: 'linux', cpu: 'x86_64') end end - def with_compilers(recipe, host_prefix: false, c_compiler: 'gcc', cxx_compiler: 'g++') - mock = MiniTest::Mock.new - - if host_prefix - mock.expect(:call, true, ["#{recipe.host}-#{c_compiler}"]) - mock.expect(:call, true, ["#{recipe.host}-#{cxx_compiler}"]) - else - mock.expect(:call, false, ["#{recipe.host}-#{c_compiler}"]) - mock.expect(:call, true, [c_compiler]) - mock.expect(:call, false, ["#{recipe.host}-#{cxx_compiler}"]) - mock.expect(:call, true, [cxx_compiler]) - end - - recipe.stub(:which, mock) do - yield + def with_compilers(c_compiler: 'gcc', cxx_compiler: 'g++') + @recipe.stub(:cc_cmd, c_compiler) do + @recipe.stub(:cxx_cmd, cxx_compiler) do + yield + end end end diff --git a/test/test_cook.rb b/test/test_cook.rb index 031a43a..fd5d3b8 100644 --- a/test/test_cook.rb +++ b/test/test_cook.rb @@ -98,6 +98,18 @@ def test_cc_command_configuration assert_equal("asdf", MiniPortile.new("test", "1.0.0", gcc_command: "xyzzy").gcc_cmd) end end + + def test_cxx_command_configuration + without_env("CXX") do + expected_compiler = RbConfig::CONFIG["CXX"] || "g++" + assert_equal(expected_compiler, MiniPortile.new("test", "1.0.0").cxx_cmd) + assert_equal("xyzzy", MiniPortile.new("test", "1.0.0", cxx_command: "xyzzy").cxx_cmd) + end + with_env("CXX"=>"asdf") do + assert_equal("asdf", MiniPortile.new("test", "1.0.0").cxx_cmd) + assert_equal("asdf", MiniPortile.new("test", "1.0.0", cxx_command: "xyzzy").cxx_cmd) + end + end end