Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cxx_cmd which parallels cc_cmd #144

Merged
merged 2 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
5 changes: 5 additions & 0 deletions lib/mini_portile2/mini_portile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
38 changes: 5 additions & 33 deletions lib/mini_portile2/mini_portile_cmake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
require 'erb'
require 'mini_portile2'

puts "#{__FILE__}:#{__LINE__}: relevant RbConfig::CONFIG values:"
%w[target_os target_cpu CC CXX].each do |key|
puts "- #{key}: #{RbConfig::CONFIG[key].inspect}"
end

class TestCase < Minitest::Test
include Minitest::Hooks

Expand Down
81 changes: 29 additions & 52 deletions test/test_cmake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
[
Expand All @@ -123,47 +117,44 @@ def test_configure_defaults_with_freebsd
"-DCMAKE_CXX_COMPILER=c++",
"-DCMAKE_BUILD_TYPE=Release"
],
recipe.configure_defaults)
@recipe.configure_defaults)
end
end
end
end
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
end
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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
12 changes: 12 additions & 0 deletions test/test_cook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
Loading