mkmf-lite 0.7.2 → 0.7.4

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: 7e85aa72d40bbefbc3868cfce08cdadcd27f2715f96aead7b7055808ea724f5f
4
- data.tar.gz: 415625060ad8e4d9d6998f581af4eeb0adb5c69f0a012a827956cfc19f173ff7
3
+ metadata.gz: 83a4d986b70bc7bcd5c5787245bd5b76f335dc6079124d6bdd18847b128dcb3c
4
+ data.tar.gz: c688342d4e86a77221dbbd2dd12fc3c3a77ac92892bb4aab230af11bc50ff5ec
5
5
  SHA512:
6
- metadata.gz: af36e6b2ffc4d90cb1faf28ebe141547b2459819f95caf6b5dded3e51dce35667eb8ea9b0bf81443146495f42c341f56f81d27d3b7b3a7862e9c2a492b4c848d
7
- data.tar.gz: f78fc8d5f051406690b1d7b1b362868be38fd25a45ad140cec40bc9aaf58d0ebdf2a2b53b5c0ca4660954266938be91405660bee3fe85ad0f3a340002d92e25b
6
+ metadata.gz: c36047013680595f8776cd8e87813ccf4fdf2aac43056d6ffc676c61c262f502e8c3114b3a09ca6b1610eede8ea6c3b59bce4e8631e0e785afd385c789d61aad
7
+ data.tar.gz: 0ef5c1481603d4ffdc840d6f468f4ddcaa0e03b81f2648e6395f48df72b21d772c24ff17638db365d2c1316f57e24cff8ac6880b7895b5710178625df43bf4be
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.7.4 - 23-Dec-2025
2
+ * Added have_library method.
3
+
4
+ ## 0.7.3 - 21-Mar-2025
5
+ * Added check_offsetof method.
6
+
1
7
  ## 0.7.2 - 13-Mar-2025
2
8
  * Allow option of adding directories to check_sizeof and check_valueof methods.
3
9
 
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.2'
19
+ MKMF_LITE_VERSION = '0.7.4'
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'
@@ -77,14 +83,7 @@ module Mkmf
77
83
  def have_header(header, *directories)
78
84
  erb = ERB.new(read_template('have_header.erb'))
79
85
  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
86
+ options = build_directory_options(directories)
88
87
 
89
88
  try_to_compile(code, options)
90
89
  end
@@ -112,6 +111,25 @@ module Mkmf
112
111
 
113
112
  memoize :have_func
114
113
 
114
+ # Check for the presence of the given +library+. You may optionally
115
+ # provide a +function+ name to check for within that library, as well
116
+ # as any additional +headers+.
117
+ #
118
+ # Returns true if the library can be linked, or false otherwise.
119
+ #
120
+ def have_library(library, function = nil, headers = [])
121
+ headers = get_header_string(headers)
122
+ erb = ERB.new(read_template('have_library.erb'))
123
+ code = erb.result(binding)
124
+
125
+ # Build link options with the library
126
+ link_options = windows_with_cl_compiler? ? "#{library}.lib" : "-l#{library}"
127
+
128
+ try_to_compile(code, nil, link_options)
129
+ end
130
+
131
+ memoize :have_library
132
+
115
133
  # Checks whether or not the struct of type +struct_type+ contains the
116
134
  # +struct_member+. If it does not, or the struct type cannot be found,
117
135
  # then false is returned.
@@ -139,14 +157,7 @@ module Mkmf
139
157
  headers = get_header_string(headers)
140
158
  erb = ERB.new(read_template('check_valueof.erb'))
141
159
  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
160
+ options = build_directory_options(directories)
150
161
 
151
162
  try_to_execute(code, options)
152
163
  end
@@ -170,22 +181,73 @@ module Mkmf
170
181
  headers = get_header_string(headers)
171
182
  erb = ERB.new(read_template('check_sizeof.erb'))
172
183
  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
184
+ options = build_directory_options(directories)
181
185
 
182
186
  try_to_execute(code, options)
183
187
  end
184
188
 
185
189
  memoize :check_sizeof
186
190
 
191
+ # Returns the offset of +field+ within +struct_type+ using +headers+,
192
+ # or common headers, plus stddef.h, if no headers are specified.
193
+ #
194
+ # If this method fails an error is raised. This could happen if the field
195
+ # can't be found and/or the header files do not include the indicated type.
196
+ # It will also fail if the field is a bit field.
197
+ #
198
+ # Example:
199
+ #
200
+ # class Foo
201
+ # include Mkmf::Lite
202
+ # utsname = check_offsetof('struct utsname', 'release', 'sys/utsname.h')
203
+ # end
204
+ #
205
+ def check_offsetof(struct_type, field, headers = [], *directories)
206
+ headers = get_header_string(headers)
207
+ erb = ERB.new(read_template('check_offsetof.erb'))
208
+ code = erb.result(binding)
209
+ options = build_directory_options(directories)
210
+
211
+ try_to_execute(code, options)
212
+ end
213
+
214
+ memoize :check_offsetof
215
+
187
216
  private
188
217
 
218
+ def build_directory_options(directories)
219
+ return nil if directories.empty?
220
+
221
+ directories.map { |dir| "-I#{dir}" }.join(' ')
222
+ end
223
+
224
+ def build_compile_command(command_options = nil, library_options = nil)
225
+ command_parts = [cpp_command]
226
+ command_parts << command_options if command_options
227
+ command_parts << cpp_libraries if cpp_libraries
228
+ command_parts << cpp_defs
229
+ command_parts << cpp_out_file
230
+ command_parts << cpp_source_file
231
+ command_parts << library_options if library_options
232
+
233
+ command_parts.compact.join(' ')
234
+ end
235
+
236
+ def with_suppressed_output
237
+ stderr_orig = $stderr.dup
238
+ stdout_orig = $stdout.dup
239
+
240
+ $stderr.reopen(IO::NULL)
241
+ $stdout.reopen(IO::NULL)
242
+
243
+ yield
244
+ ensure
245
+ $stderr.reopen(stderr_orig)
246
+ $stdout.reopen(stdout_orig)
247
+ stderr_orig.close
248
+ stdout_orig.close
249
+ end
250
+
189
251
  # Take an array of header file names (or convert it to an array if it's a
190
252
  # single argument), add the COMMON_HEADERS, flatten it out and remove any
191
253
  # duplicates.
@@ -196,21 +258,20 @@ module Mkmf
196
258
  # This string is then to be used at the top of the ERB templates.
197
259
  #
198
260
  def get_header_string(headers)
199
- headers = [headers] unless headers.is_a?(Array)
261
+ headers = Array(headers)
200
262
 
201
263
  common_headers = RbConfig::CONFIG['COMMON_HEADERS']
202
264
 
203
265
  if common_headers.nil? || common_headers.empty?
204
266
  if headers.empty?
205
267
  headers = ['stdio.h', 'stdlib.h']
206
- headers += 'windows.h' if File::ALT_SEPARATOR
268
+ headers << 'windows.h' if File::ALT_SEPARATOR
207
269
  end
208
270
  else
209
271
  headers += common_headers.split
210
272
  end
211
273
 
212
- headers = headers.flatten.uniq
213
- headers.map{ |h| "#include <#{h}>" }.join("\n")
274
+ headers.flatten.uniq.map { |h| "#include <#{h}>" }.join("\n")
214
275
  end
215
276
 
216
277
  # Create a temporary bit of C source code in the temp directory, and
@@ -223,50 +284,32 @@ module Mkmf
223
284
  # error is raised if the compilation step fails.
224
285
  #
225
286
  def try_to_execute(code, command_options = nil)
226
- begin
227
- result = 0
228
-
229
- stderr_orig = $stderr.dup
230
- stdout_orig = $stdout.dup
231
-
232
- Dir.chdir(Dir.tmpdir) do
233
- File.write(cpp_source_file, code)
287
+ result = 0
234
288
 
235
- if command_options
236
- command = "#{cpp_command} #{command_options} #{cpp_libraries} #{cpp_defs} "
237
- else
238
- command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} "
239
- end
240
-
241
- command += "#{cpp_out_file} "
242
- command += cpp_source_file
289
+ Dir.chdir(Dir.tmpdir) do
290
+ File.write(cpp_source_file, code)
291
+ command = build_compile_command(command_options)
243
292
 
244
- # Temporarily close these
245
- $stderr.reopen(IO::NULL)
246
- $stdout.reopen(IO::NULL)
293
+ compilation_successful = with_suppressed_output { system(command) }
247
294
 
248
- if system(command)
249
- $stdout.reopen(stdout_orig) # We need this back for open3 to work.
295
+ if compilation_successful
296
+ conftest = File::ALT_SEPARATOR ? 'conftest.exe' : './conftest.exe'
250
297
 
251
- conftest = File::ALT_SEPARATOR ? 'conftest.exe' : './conftest.exe'
252
-
253
- Open3.popen3(conftest) do |stdin, stdout, stderr|
254
- stdin.close
255
- stderr.close
256
- result = stdout.gets.chomp.to_i
257
- end
258
- else
259
- raise "Failed to compile source code with command '#{command}':\n===\n#{code}==="
298
+ Open3.popen3(conftest) do |stdin, stdout, stderr|
299
+ stdin.close
300
+ stderr.close
301
+ output = stdout.gets
302
+ result = output&.chomp&.to_i || 0
260
303
  end
304
+ else
305
+ raise StandardError, "Failed to compile source code with command '#{command}':\n===\n#{code}==="
261
306
  end
262
- ensure
263
- FileUtils.rm_f(cpp_source_file)
264
- FileUtils.rm_f(cpp_out_file)
265
- $stderr.reopen(stderr_orig)
266
- $stdout.reopen(stdout_orig)
267
307
  end
268
308
 
269
309
  result
310
+ ensure
311
+ FileUtils.rm_f(File.join(Dir.tmpdir, cpp_source_file))
312
+ FileUtils.rm_f(File.join(Dir.tmpdir, 'conftest.exe'))
270
313
  end
271
314
 
272
315
  # Create a temporary bit of C source code in the temp directory, and
@@ -276,36 +319,16 @@ module Mkmf
276
319
  # Note that $stderr is temporarily redirected to the null device because
277
320
  # we don't actually care about the reason for failure.
278
321
  #
279
- def try_to_compile(code, command_options = nil)
280
- begin
281
- boolean = false
282
- stderr_orig = $stderr.dup
283
- stdout_orig = $stdout.dup
284
-
285
- Dir.chdir(Dir.tmpdir) do
286
- File.write(cpp_source_file, code)
287
-
288
- if command_options
289
- command = "#{cpp_command} #{command_options} #{cpp_libraries} #{cpp_defs} "
290
- else
291
- command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} "
292
- end
322
+ def try_to_compile(code, command_options = nil, library_options = nil)
323
+ Dir.chdir(Dir.tmpdir) do
324
+ File.write(cpp_source_file, code)
325
+ command = build_compile_command(command_options, library_options)
293
326
 
294
- command += "#{cpp_out_file} "
295
- command += cpp_source_file
296
-
297
- $stderr.reopen(IO::NULL)
298
- $stdout.reopen(IO::NULL)
299
- boolean = system(command)
300
- end
301
- ensure
302
- FileUtils.rm_f(cpp_source_file)
303
- FileUtils.rm_f(cpp_out_file)
304
- $stdout.reopen(stdout_orig)
305
- $stderr.reopen(stderr_orig)
327
+ with_suppressed_output { system(command) }
306
328
  end
307
-
308
- boolean
329
+ ensure
330
+ FileUtils.rm_f(File.join(Dir.tmpdir, cpp_source_file))
331
+ FileUtils.rm_f(File.join(Dir.tmpdir, 'conftest.exe'))
309
332
  end
310
333
 
311
334
  # Slurp the contents of the template file for evaluation later.
@@ -0,0 +1,11 @@
1
+ #include <stdio.h>
2
+ #include <stddef.h>
3
+
4
+ <%= headers %>
5
+
6
+ int conftest_const = (int)(offsetof(<%= struct_type %>, <%= field %>));
7
+
8
+ int main(){
9
+ printf("%d\n", conftest_const);
10
+ return 0;
11
+ }
@@ -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.2'
6
+ spec.version = '0.7.4'
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.2')
23
+ expect(described_class::MKMF_LITE_VERSION).to eq('0.7.4')
24
24
  expect(described_class::MKMF_LITE_VERSION).to be_frozen
25
25
  end
26
26
  end
@@ -112,6 +112,33 @@ RSpec.describe Mkmf::Lite do
112
112
  end
113
113
  end
114
114
 
115
+ context 'check_offsetof' do
116
+ let(:st_field){ 'st_dev' }
117
+
118
+ example 'check_offsetof basic functionality' do
119
+ expect(subject).to respond_to(:check_offsetof)
120
+ expect{ subject.check_offsetof(st_type, st_field, st_header) }.not_to raise_error
121
+ end
122
+
123
+ example 'check_offsetof requires at least two arguments' do
124
+ expect{ subject.check_offsetof }.to raise_error(ArgumentError)
125
+ expect{ subject.check_offsetof(st_type) }.to raise_error(ArgumentError)
126
+ end
127
+
128
+ example 'check_offsetof accepts directory arguments' do
129
+ expect{ subject.check_offsetof(st_type, st_field, [st_header, 'stdlib.h'], ['/usr/include']) }.not_to raise_error
130
+ end
131
+
132
+ example 'check_offsetof returns an integer value' do
133
+ size1 = subject.check_offsetof(st_type, st_field, st_header)
134
+ size2 = subject.check_offsetof(st_type, 'st_ino', st_header)
135
+ expect(size1).to be_a(Integer)
136
+ expect(size2).to be_a(Integer)
137
+ expect(size1).to eq(0)
138
+ expect(size2).to be > size1
139
+ end
140
+ end
141
+
115
142
  context 'check_sizeof' do
116
143
  example 'check_sizeof basic functionality' do
117
144
  expect(subject).to respond_to(:check_sizeof)
@@ -137,4 +164,34 @@ RSpec.describe Mkmf::Lite do
137
164
  expect(size).to be > 0
138
165
  end
139
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
140
197
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mkmf-lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -34,7 +34,7 @@ cert_chain:
34
34
  ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
35
35
  WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
36
36
  -----END CERTIFICATE-----
37
- date: 2025-03-13 00:00:00.000000000 Z
37
+ date: 1980-01-02 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: ptools
@@ -138,13 +138,17 @@ files:
138
138
  - README.md
139
139
  - Rakefile
140
140
  - certs/djberg96_pub.pem
141
+ - conftest.c
142
+ - conftest.exe
141
143
  - lib/mkmf-lite.rb
142
144
  - lib/mkmf/lite.rb
145
+ - lib/mkmf/templates/check_offsetof.erb
143
146
  - lib/mkmf/templates/check_sizeof.erb
144
147
  - lib/mkmf/templates/check_valueof.erb
145
148
  - lib/mkmf/templates/have_func.erb
146
149
  - lib/mkmf/templates/have_func_pointer.erb
147
150
  - lib/mkmf/templates/have_header.erb
151
+ - lib/mkmf/templates/have_library.erb
148
152
  - lib/mkmf/templates/have_struct_member.erb
149
153
  - mkmf-lite.gemspec
150
154
  - spec/mkmf_lite_spec.rb
@@ -175,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
179
  - !ruby/object:Gem::Version
176
180
  version: '0'
177
181
  requirements: []
178
- rubygems_version: 3.6.5
182
+ rubygems_version: 3.7.2
179
183
  specification_version: 4
180
184
  summary: A lighter version of mkmf designed for use as a library
181
185
  test_files:
metadata.gz.sig CHANGED
Binary file