mkmf-lite 0.7.3 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 726b5a45c22c5700645950241fabc40621f7a1ec9f57a20fffd212623a41acd0
4
- data.tar.gz: 34bc9e1d6d1c3bba0a9c73cfd7d899fda171054c73dfaaeec6305f246f0fe497
3
+ metadata.gz: 3d3876fab22593f1d61c44718bc4fa4a582ce639230745ebed95c61b99a2a164
4
+ data.tar.gz: 74188f32f661c473e575412c095ea7cdd78493af4a25bfbde1934bad604b04ec
5
5
  SHA512:
6
- metadata.gz: b5e4afd22216317af2dbb01ea8ead2339976c00276774b1a9e6b5a72e04e6d6ecb097863f6366ce7de93628299440a44b0663db245964d8c30bc310f72d14021
7
- data.tar.gz: 0d132571eb8b470886c5e2bce7c5b80b0de36ffe563dd929d7ba479173125827a643b8d63584d7b76a6d05c8db72dd1f5c35b095f38cad707d06d29541c4103c
6
+ metadata.gz: 30e2efbd8e802dbcf0237a9a5a514e7f39218702a0713ae7868135b06b9052e43be975e4a4ca9e347135f437ff1d48bbeaf8692d7d76db523b76f26aaaf1072d
7
+ data.tar.gz: d7c9e01c1cdcb5f8ad94a7a2a82c16c143f2e4140da64a78c7f399a69e15830270b99c290c0844577cd738a136266490fa1cec5e376e45d50e80c4d8ad2448ca
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
+ ## 0.7.5 - 24-Dec-2025
2
+ * Automatically include homebrew lib for have_library on Macs.
3
+ * Modified the have_library to work with or without leading "lib".
4
+
5
+ ## 0.7.4 - 23-Dec-2025
6
+ * Added have_library method.
7
+
1
8
  ## 0.7.3 - 21-Mar-2025
2
- * Add check_offsetof method.
9
+ * Added check_offsetof method.
3
10
 
4
11
  ## 0.7.2 - 13-Mar-2025
5
12
  * Allow option of adding directories to check_sizeof and check_valueof methods.
data/README.md CHANGED
@@ -54,7 +54,7 @@ JRuby may emit warnings on some platforms.
54
54
  Apache-2.0
55
55
 
56
56
  ## Copyright
57
- (C) 2010-2024 Daniel J. Berger
57
+ (C) 2010-2025 Daniel J. Berger
58
58
  All Rights Reserved
59
59
 
60
60
  ## Warranty
data/Rakefile CHANGED
@@ -24,7 +24,10 @@ end
24
24
  RuboCop::RakeTask.new
25
25
 
26
26
  desc "Run the test suite"
27
- RSpec::Core::RakeTask.new(:spec)
27
+ RSpec::Core::RakeTask.new(:spec) do |t|
28
+ t.verbose = false
29
+ t.rspec_opts = '-f documentation -w'
30
+ end
28
31
 
29
32
  # Clean up afterwards
30
33
  Rake::Task[:spec].enhance do
data/conftest.c ADDED
@@ -0,0 +1,5 @@
1
+ #include <foobar.h>
2
+
3
+ int main(){
4
+ return 0;
5
+ }
data/conftest.exe ADDED
Binary file
data/lib/mkmf/lite.rb CHANGED
@@ -16,7 +16,7 @@ module Mkmf
16
16
  extend Memoist
17
17
 
18
18
  # The version of the mkmf-lite library
19
- MKMF_LITE_VERSION = '0.7.3'
19
+ MKMF_LITE_VERSION = '0.7.5'
20
20
 
21
21
  private
22
22
 
@@ -25,15 +25,22 @@ module Mkmf
25
25
  end
26
26
 
27
27
  def jruby?
28
- defined?(JRUBY_VERSION) ? true : false
28
+ defined?(JRUBY_VERSION)
29
29
  end
30
30
 
31
31
  memoize :jruby?
32
32
 
33
+ def windows_with_cl_compiler?
34
+ File::ALT_SEPARATOR && RbConfig::CONFIG['CPP']&.match?(/^cl/)
35
+ end
36
+
37
+ memoize :windows_with_cl_compiler?
38
+
33
39
  # rubocop:disable Layout/LineLength
34
40
  def cpp_command
35
41
  command = RbConfig::CONFIG['CC'] || RbConfig::CONFIG['CPP'] || File.which('cc') || File.which('gcc') || File.which('cl')
36
- raise 'Compiler not found' unless command
42
+ raise StandardError, 'Compiler not found' unless command
43
+
37
44
  command
38
45
  end
39
46
  # rubocop:enable Layout/LineLength
@@ -45,7 +52,7 @@ module Mkmf
45
52
  end
46
53
 
47
54
  def cpp_out_file
48
- if File::ALT_SEPARATOR && RbConfig::CONFIG['CPP'] =~ /^cl/
55
+ if windows_with_cl_compiler?
49
56
  '/Feconftest.exe'
50
57
  else
51
58
  '-o conftest.exe'
@@ -55,10 +62,9 @@ module Mkmf
55
62
  memoize :cpp_out_file
56
63
 
57
64
  def cpp_libraries
58
- return if File::ALT_SEPARATOR && RbConfig::CONFIG['CPP'] =~ /^cl/
59
- return if jruby?
65
+ return nil if windows_with_cl_compiler? || jruby?
60
66
 
61
- if cpp_command =~ /clang/i
67
+ if cpp_command.match?(/clang/i)
62
68
  '-Lrt -Ldl -Lcrypt -Lm'
63
69
  else
64
70
  '-lrt -ldl -lcrypt -lm'
@@ -67,6 +73,22 @@ module Mkmf
67
73
 
68
74
  memoize :cpp_libraries
69
75
 
76
+ def cpp_library_paths
77
+ paths = []
78
+
79
+ # Add Homebrew library paths on macOS
80
+ if RbConfig::CONFIG['host_os'].match?(/darwin/)
81
+ # Apple Silicon Macs
82
+ paths << '-L/opt/homebrew/lib' if File.directory?('/opt/homebrew/lib')
83
+ # Intel Macs
84
+ paths << '-L/usr/local/lib' if File.directory?('/usr/local/lib')
85
+ end
86
+
87
+ paths.empty? ? nil : paths.join(' ')
88
+ end
89
+
90
+ memoize :cpp_library_paths
91
+
70
92
  public
71
93
 
72
94
  # Check for the presence of the given +header+ file. You may optionally
@@ -77,14 +99,7 @@ module Mkmf
77
99
  def have_header(header, *directories)
78
100
  erb = ERB.new(read_template('have_header.erb'))
79
101
  code = erb.result(binding)
80
-
81
- if directories.empty?
82
- options = nil
83
- else
84
- options = ''
85
- directories.each{ |dir| options += "-I#{dir} " }
86
- options.rstrip!
87
- end
102
+ options = build_directory_options(directories)
88
103
 
89
104
  try_to_compile(code, options)
90
105
  end
@@ -112,6 +127,32 @@ module Mkmf
112
127
 
113
128
  memoize :have_func
114
129
 
130
+ # Check for the presence of the given +library+. You may optionally
131
+ # provide a +function+ name to check for within that library, as well
132
+ # as any additional +headers+.
133
+ #
134
+ # Returns true if the library can be linked, or false otherwise.
135
+ #
136
+ # Note: The library name should not include the 'lib' prefix or file
137
+ # extension. For example, use 'xerces-c' not 'libxerces-c' or 'libxerces-c.dylib'.
138
+ # However, if the 'lib' prefix is provided, it will be automatically stripped.
139
+ #
140
+ def have_library(library, function = nil, headers = [])
141
+ # Strip 'lib' prefix if present (e.g., 'libxerces-c' -> 'xerces-c')
142
+ library = library.sub(/^lib/, '') unless windows_with_cl_compiler?
143
+
144
+ headers = get_header_string(headers)
145
+ erb = ERB.new(read_template('have_library.erb'))
146
+ code = erb.result(binding)
147
+
148
+ # Build link options with the library
149
+ link_options = windows_with_cl_compiler? ? "#{library}.lib" : "-l#{library}"
150
+
151
+ try_to_compile(code, nil, link_options)
152
+ end
153
+
154
+ memoize :have_library
155
+
115
156
  # Checks whether or not the struct of type +struct_type+ contains the
116
157
  # +struct_member+. If it does not, or the struct type cannot be found,
117
158
  # then false is returned.
@@ -139,14 +180,7 @@ module Mkmf
139
180
  headers = get_header_string(headers)
140
181
  erb = ERB.new(read_template('check_valueof.erb'))
141
182
  code = erb.result(binding)
142
-
143
- if directories.empty?
144
- options = nil
145
- else
146
- options = ''
147
- directories.each{ |dir| options += "-I#{dir} " }
148
- options.rstrip!
149
- end
183
+ options = build_directory_options(directories)
150
184
 
151
185
  try_to_execute(code, options)
152
186
  end
@@ -170,14 +204,7 @@ module Mkmf
170
204
  headers = get_header_string(headers)
171
205
  erb = ERB.new(read_template('check_sizeof.erb'))
172
206
  code = erb.result(binding)
173
-
174
- if directories.empty?
175
- options = nil
176
- else
177
- options = ''
178
- directories.each{ |dir| options += "-I#{dir} " }
179
- options.rstrip!
180
- end
207
+ options = build_directory_options(directories)
181
208
 
182
209
  try_to_execute(code, options)
183
210
  end
@@ -202,14 +229,7 @@ module Mkmf
202
229
  headers = get_header_string(headers)
203
230
  erb = ERB.new(read_template('check_offsetof.erb'))
204
231
  code = erb.result(binding)
205
-
206
- if directories.empty?
207
- options = nil
208
- else
209
- options = ''
210
- directories.each{ |dir| options += "-I#{dir} " }
211
- options.rstrip!
212
- end
232
+ options = build_directory_options(directories)
213
233
 
214
234
  try_to_execute(code, options)
215
235
  end
@@ -218,6 +238,40 @@ module Mkmf
218
238
 
219
239
  private
220
240
 
241
+ def build_directory_options(directories)
242
+ return nil if directories.empty?
243
+
244
+ directories.map { |dir| "-I#{dir}" }.join(' ')
245
+ end
246
+
247
+ def build_compile_command(command_options = nil, library_options = nil)
248
+ command_parts = [cpp_command]
249
+ command_parts << command_options if command_options
250
+ command_parts << cpp_library_paths if cpp_library_paths
251
+ command_parts << cpp_libraries if cpp_libraries
252
+ command_parts << cpp_defs
253
+ command_parts << cpp_out_file
254
+ command_parts << cpp_source_file
255
+ command_parts << library_options if library_options
256
+
257
+ command_parts.compact.join(' ')
258
+ end
259
+
260
+ def with_suppressed_output
261
+ stderr_orig = $stderr.dup
262
+ stdout_orig = $stdout.dup
263
+
264
+ $stderr.reopen(IO::NULL)
265
+ $stdout.reopen(IO::NULL)
266
+
267
+ yield
268
+ ensure
269
+ $stderr.reopen(stderr_orig)
270
+ $stdout.reopen(stdout_orig)
271
+ stderr_orig.close
272
+ stdout_orig.close
273
+ end
274
+
221
275
  # Take an array of header file names (or convert it to an array if it's a
222
276
  # single argument), add the COMMON_HEADERS, flatten it out and remove any
223
277
  # duplicates.
@@ -228,21 +282,20 @@ module Mkmf
228
282
  # This string is then to be used at the top of the ERB templates.
229
283
  #
230
284
  def get_header_string(headers)
231
- headers = [headers] unless headers.is_a?(Array)
285
+ headers = Array(headers)
232
286
 
233
287
  common_headers = RbConfig::CONFIG['COMMON_HEADERS']
234
288
 
235
289
  if common_headers.nil? || common_headers.empty?
236
290
  if headers.empty?
237
291
  headers = ['stdio.h', 'stdlib.h']
238
- headers += 'windows.h' if File::ALT_SEPARATOR
292
+ headers << 'windows.h' if File::ALT_SEPARATOR
239
293
  end
240
294
  else
241
295
  headers += common_headers.split
242
296
  end
243
297
 
244
- headers = headers.flatten.uniq
245
- headers.map{ |h| "#include <#{h}>" }.join("\n")
298
+ headers.flatten.uniq.map { |h| "#include <#{h}>" }.join("\n")
246
299
  end
247
300
 
248
301
  # Create a temporary bit of C source code in the temp directory, and
@@ -255,50 +308,32 @@ module Mkmf
255
308
  # error is raised if the compilation step fails.
256
309
  #
257
310
  def try_to_execute(code, command_options = nil)
258
- begin
259
- result = 0
260
-
261
- stderr_orig = $stderr.dup
262
- stdout_orig = $stdout.dup
263
-
264
- Dir.chdir(Dir.tmpdir) do
265
- File.write(cpp_source_file, code)
266
-
267
- if command_options
268
- command = "#{cpp_command} #{command_options} #{cpp_libraries} #{cpp_defs} "
269
- else
270
- command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} "
271
- end
272
-
273
- command += "#{cpp_out_file} "
274
- command += cpp_source_file
311
+ result = 0
275
312
 
276
- # Temporarily close these
277
- $stderr.reopen(IO::NULL)
278
- $stdout.reopen(IO::NULL)
313
+ Dir.chdir(Dir.tmpdir) do
314
+ File.write(cpp_source_file, code)
315
+ command = build_compile_command(command_options)
279
316
 
280
- if system(command)
281
- $stdout.reopen(stdout_orig) # We need this back for open3 to work.
317
+ compilation_successful = with_suppressed_output { system(command) }
282
318
 
283
- conftest = File::ALT_SEPARATOR ? 'conftest.exe' : './conftest.exe'
319
+ if compilation_successful
320
+ conftest = File::ALT_SEPARATOR ? 'conftest.exe' : './conftest.exe'
284
321
 
285
- Open3.popen3(conftest) do |stdin, stdout, stderr|
286
- stdin.close
287
- stderr.close
288
- result = stdout.gets.chomp.to_i
289
- end
290
- else
291
- raise "Failed to compile source code with command '#{command}':\n===\n#{code}==="
322
+ Open3.popen3(conftest) do |stdin, stdout, stderr|
323
+ stdin.close
324
+ stderr.close
325
+ output = stdout.gets
326
+ result = output&.chomp&.to_i || 0
292
327
  end
328
+ else
329
+ raise StandardError, "Failed to compile source code with command '#{command}':\n===\n#{code}==="
293
330
  end
294
- ensure
295
- FileUtils.rm_f(cpp_source_file)
296
- FileUtils.rm_f(cpp_out_file)
297
- $stderr.reopen(stderr_orig)
298
- $stdout.reopen(stdout_orig)
299
331
  end
300
332
 
301
333
  result
334
+ ensure
335
+ FileUtils.rm_f(File.join(Dir.tmpdir, cpp_source_file))
336
+ FileUtils.rm_f(File.join(Dir.tmpdir, 'conftest.exe'))
302
337
  end
303
338
 
304
339
  # Create a temporary bit of C source code in the temp directory, and
@@ -308,36 +343,16 @@ module Mkmf
308
343
  # Note that $stderr is temporarily redirected to the null device because
309
344
  # we don't actually care about the reason for failure.
310
345
  #
311
- def try_to_compile(code, command_options = nil)
312
- begin
313
- boolean = false
314
- stderr_orig = $stderr.dup
315
- stdout_orig = $stdout.dup
316
-
317
- Dir.chdir(Dir.tmpdir) do
318
- File.write(cpp_source_file, code)
319
-
320
- if command_options
321
- command = "#{cpp_command} #{command_options} #{cpp_libraries} #{cpp_defs} "
322
- else
323
- command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} "
324
- end
346
+ def try_to_compile(code, command_options = nil, library_options = nil)
347
+ Dir.chdir(Dir.tmpdir) do
348
+ File.write(cpp_source_file, code)
349
+ command = build_compile_command(command_options, library_options)
325
350
 
326
- command += "#{cpp_out_file} "
327
- command += cpp_source_file
328
-
329
- $stderr.reopen(IO::NULL)
330
- $stdout.reopen(IO::NULL)
331
- boolean = system(command)
332
- end
333
- ensure
334
- FileUtils.rm_f(cpp_source_file)
335
- FileUtils.rm_f(cpp_out_file)
336
- $stdout.reopen(stdout_orig)
337
- $stderr.reopen(stderr_orig)
351
+ with_suppressed_output { system(command) }
338
352
  end
339
-
340
- boolean
353
+ ensure
354
+ FileUtils.rm_f(File.join(Dir.tmpdir, cpp_source_file))
355
+ FileUtils.rm_f(File.join(Dir.tmpdir, 'conftest.exe'))
341
356
  end
342
357
 
343
358
  # Slurp the contents of the template file for evaluation later.
@@ -0,0 +1,10 @@
1
+ <%= headers %>
2
+
3
+ int main(){
4
+ <% if function %>
5
+ void *p = (void *)&<%= function %>;
6
+ return !p;
7
+ <% else %>
8
+ return 0;
9
+ <% end %>
10
+ }
data/mkmf-lite.gemspec CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'mkmf-lite'
5
5
  spec.summary = 'A lighter version of mkmf designed for use as a library'
6
- spec.version = '0.7.3'
6
+ spec.version = '0.7.5'
7
7
  spec.author = 'Daniel J. Berger'
8
8
  spec.license = 'Apache-2.0'
9
9
  spec.email = 'djberg96@gmail.com'
@@ -20,7 +20,7 @@ RSpec.describe Mkmf::Lite do
20
20
 
21
21
  describe 'constants' do
22
22
  example 'version information' do
23
- expect(described_class::MKMF_LITE_VERSION).to eq('0.7.3')
23
+ expect(described_class::MKMF_LITE_VERSION).to eq('0.7.5')
24
24
  expect(described_class::MKMF_LITE_VERSION).to be_frozen
25
25
  end
26
26
  end
@@ -164,4 +164,34 @@ RSpec.describe Mkmf::Lite do
164
164
  expect(size).to be > 0
165
165
  end
166
166
  end
167
+
168
+ context 'have_library' do
169
+ example 'have_library basic functionality' do
170
+ expect(subject).to respond_to(:have_library)
171
+ end
172
+
173
+ example 'have_library returns expected boolean value' do
174
+ expect(subject.have_library('c')).to be(true)
175
+ expect(subject.have_library('m')).to be(true)
176
+ expect(subject.have_library('nonexistent_library_xyz')).to be(false)
177
+ end
178
+
179
+ example 'have_library with function argument returns expected boolean value' do
180
+ expect(subject.have_library('m', 'sqrt', 'math.h')).to be(true)
181
+ expect(subject.have_library('m', 'nonexistent_function_xyz', 'math.h')).to be(false)
182
+ end
183
+
184
+ example 'have_library with headers argument works correctly' do
185
+ expect{ subject.have_library('m', 'sqrt', 'math.h') }.not_to raise_error
186
+ expect(subject.have_library('m', 'sqrt', 'math.h')).to be(true)
187
+ end
188
+
189
+ example 'have_library requires at least one argument' do
190
+ expect{ subject.have_library }.to raise_error(ArgumentError)
191
+ end
192
+
193
+ example 'have_library accepts a maximum of three arguments' do
194
+ expect{ subject.have_library('m', 'sqrt', 'math.h', 'bogus') }.to raise_error(ArgumentError)
195
+ end
196
+ end
167
197
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,11 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mkmf-lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain:
11
10
  - |
@@ -35,7 +34,7 @@ cert_chain:
35
34
  ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
36
35
  WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
37
36
  -----END CERTIFICATE-----
38
- date: 2025-03-22 00:00:00.000000000 Z
37
+ date: 1980-01-02 00:00:00.000000000 Z
39
38
  dependencies:
40
39
  - !ruby/object:Gem::Dependency
41
40
  name: ptools
@@ -139,6 +138,8 @@ files:
139
138
  - README.md
140
139
  - Rakefile
141
140
  - certs/djberg96_pub.pem
141
+ - conftest.c
142
+ - conftest.exe
142
143
  - lib/mkmf-lite.rb
143
144
  - lib/mkmf/lite.rb
144
145
  - lib/mkmf/templates/check_offsetof.erb
@@ -147,6 +148,7 @@ files:
147
148
  - lib/mkmf/templates/have_func.erb
148
149
  - lib/mkmf/templates/have_func_pointer.erb
149
150
  - lib/mkmf/templates/have_header.erb
151
+ - lib/mkmf/templates/have_library.erb
150
152
  - lib/mkmf/templates/have_struct_member.erb
151
153
  - mkmf-lite.gemspec
152
154
  - spec/mkmf_lite_spec.rb
@@ -163,7 +165,6 @@ metadata:
163
165
  rubygems_mfa_required: 'true'
164
166
  github_repo: https://github.com/djberg96/mkmf-lite
165
167
  funding_uri: https://github.com/sponsors/djberg96
166
- post_install_message:
167
168
  rdoc_options: []
168
169
  require_paths:
169
170
  - lib
@@ -178,8 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
179
  - !ruby/object:Gem::Version
179
180
  version: '0'
180
181
  requirements: []
181
- rubygems_version: 3.5.22
182
- signing_key:
182
+ rubygems_version: 3.7.2
183
183
  specification_version: 4
184
184
  summary: A lighter version of mkmf designed for use as a library
185
185
  test_files:
metadata.gz.sig CHANGED
Binary file