mkmf-lite 0.7.5 → 0.8.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +8 -0
- data/ROADMAP.md +104 -0
- data/lib/mkmf/lite.rb +58 -73
- data/mkmf-lite.gemspec +1 -1
- data/spec/mkmf_lite_spec.rb +37 -1
- data.tar.gz.sig +0 -0
- metadata +3 -4
- metadata.gz.sig +0 -0
- data/conftest.c +0 -5
- data/conftest.exe +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 221bc258ee206eb8c19c1705bdcaa769326508d901d8f8720d1b60e7e704ca5c
|
|
4
|
+
data.tar.gz: 3383b7a19d218372b56c2e8a1938af79dcdd2b4636c4fc555069190ccfcb5cb5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 53fd358a2dcdab183376c2d809e4c305b5ff022a81e0aa21a75041019745194adc946e1ed54005ea74a0a17f3b7b476efc7227576ae40bf0b3533b64ebce84b6
|
|
7
|
+
data.tar.gz: 291f1e2ac0b2eb7c84501dd5d82d8309569951230f5742f712ab6951bc8bcc7e2c164e96cf944923d93b61d486e9863ccaf9413bfe00cc3b0c4ecdd41c614f12
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.8.0 - 29-Jun-2026
|
|
2
|
+
* Removed implicit Linux-style library flags from compiler probes.
|
|
3
|
+
* Compile probes now use argv-style command execution and per-probe temporary
|
|
4
|
+
directories.
|
|
5
|
+
* Improved support for include directories with spaces.
|
|
6
|
+
* Added FreeBSD CI coverage.
|
|
7
|
+
* Updated RuboCop configuration for current rubocop-rspec.
|
|
8
|
+
|
|
1
9
|
## 0.7.5 - 24-Dec-2025
|
|
2
10
|
* Automatically include homebrew lib for have_library on Macs.
|
|
3
11
|
* Modified the have_library to work with or without leading "lib".
|
data/ROADMAP.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
This branch focuses on making `mkmf-lite` more platform-neutral, safer to use
|
|
4
|
+
inside applications, and easier to validate across Unix-like systems. The main
|
|
5
|
+
goal is to avoid FreeBSD-specific special cases where a more general portability
|
|
6
|
+
improvement would solve the same problem.
|
|
7
|
+
|
|
8
|
+
## 0.8.0 - Portability Foundation
|
|
9
|
+
|
|
10
|
+
Keep the public API stable and harden the existing implementation.
|
|
11
|
+
|
|
12
|
+
* Replace hard-coded default libraries in `cpp_libraries`.
|
|
13
|
+
* Stop assuming Linux-style `rt`, `dl`, `crypt`, and `m` availability.
|
|
14
|
+
* Fix the clang branch that currently emits `-Lrt`, `-Ldl`, `-Lcrypt`, and
|
|
15
|
+
`-Lm`; these are library search path flags, not library link flags.
|
|
16
|
+
* Prefer Ruby's `RbConfig` values where they are appropriate, and only add
|
|
17
|
+
explicit libraries when a probe requires them.
|
|
18
|
+
* Use a per-probe temporary directory instead of shared `conftest.c` and
|
|
19
|
+
`conftest.exe` files in `Dir.tmpdir`.
|
|
20
|
+
* Avoid global `Dir.chdir` during probe compilation when practical.
|
|
21
|
+
* Replace shell-built compiler command strings with argv-style execution.
|
|
22
|
+
* Capture compiler diagnostics internally without emitting unwanted output.
|
|
23
|
+
* Add FreeBSD CI coverage, likely through Cirrus CI or a GitHub Actions
|
|
24
|
+
FreeBSD runner.
|
|
25
|
+
|
|
26
|
+
## 0.9.0 - API Improvements
|
|
27
|
+
|
|
28
|
+
Add clearer extension points while preserving the existing positional API.
|
|
29
|
+
|
|
30
|
+
* Add keyword options for include directories, library directories, compile
|
|
31
|
+
flags, and link flags.
|
|
32
|
+
* Consider examples such as:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
have_header('foo.h', include_dirs: ['/usr/local/include'])
|
|
36
|
+
have_library(
|
|
37
|
+
'foo',
|
|
38
|
+
'foo_init',
|
|
39
|
+
headers: ['foo.h'],
|
|
40
|
+
lib_dirs: ['/usr/local/lib']
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
* Add access to the last failed compile command and diagnostics.
|
|
45
|
+
* Consider a small configuration API for global defaults such as compiler,
|
|
46
|
+
include paths, library paths, and extra flags.
|
|
47
|
+
* Keep memoized public probes, but document when memoization applies and how
|
|
48
|
+
callers should think about process lifetime.
|
|
49
|
+
|
|
50
|
+
## 1.0.0 - Stable Contract
|
|
51
|
+
|
|
52
|
+
Finalize the behavior expected by downstream users.
|
|
53
|
+
|
|
54
|
+
* Document the supported public API and compatibility expectations.
|
|
55
|
+
* Remove unnecessary runtime dependencies where feasible.
|
|
56
|
+
* Document compiler selection, probe memoization, error handling, and platform
|
|
57
|
+
support.
|
|
58
|
+
* Keep the library focused on lightweight compile/link probes rather than
|
|
59
|
+
becoming a replacement for stdlib `mkmf`.
|
|
60
|
+
|
|
61
|
+
## C Probe Correctness
|
|
62
|
+
|
|
63
|
+
These improvements can land in the earliest release where they fit cleanly.
|
|
64
|
+
|
|
65
|
+
* Print `sizeof` results using `size_t` and `%zu`.
|
|
66
|
+
* Print `offsetof` results with an appropriate unsigned size format.
|
|
67
|
+
* Avoid casting sizes and offsets down to `int`.
|
|
68
|
+
* Review function probes under stricter C modes, where implicit declarations
|
|
69
|
+
and old-style function assumptions may fail.
|
|
70
|
+
* Consider compile-time assertions for probes that only need success or failure.
|
|
71
|
+
|
|
72
|
+
## Dependency Reduction
|
|
73
|
+
|
|
74
|
+
Reducing dependencies is useful, but should not distract from the portability
|
|
75
|
+
foundation.
|
|
76
|
+
|
|
77
|
+
* Remove `ptools` if it is only needed for `File.which`.
|
|
78
|
+
* Replace `File.which` with a small internal executable lookup based on
|
|
79
|
+
`ENV['PATH']`.
|
|
80
|
+
* Reevaluate `memoist` after the probe and command execution behavior is stable.
|
|
81
|
+
|
|
82
|
+
## Test Coverage
|
|
83
|
+
|
|
84
|
+
The test suite should exercise command construction and failure modes, not only
|
|
85
|
+
successful local probes.
|
|
86
|
+
|
|
87
|
+
* Add specs for generated compiler/linker arguments.
|
|
88
|
+
* Test include and library directories containing spaces.
|
|
89
|
+
* Test library names with and without a leading `lib` prefix.
|
|
90
|
+
* Test parallel probe invocations to catch temporary file collisions.
|
|
91
|
+
* Add mocked `RbConfig` coverage for Linux, macOS, FreeBSD, Windows/MSVC, and
|
|
92
|
+
JRuby.
|
|
93
|
+
* Add a regression test proving clang does not receive bogus `-Lrt`-style
|
|
94
|
+
flags.
|
|
95
|
+
|
|
96
|
+
## Documentation
|
|
97
|
+
|
|
98
|
+
Documentation should make the portability model explicit.
|
|
99
|
+
|
|
100
|
+
* Explain that probes compile tiny C programs using Ruby's configured compiler.
|
|
101
|
+
* Clarify how `mkmf-lite` differs from stdlib `mkmf`.
|
|
102
|
+
* Add FFI-oriented examples for common Unix-like use cases.
|
|
103
|
+
* Document how to pass include and library paths for ports-installed libraries,
|
|
104
|
+
especially `/usr/local/include` and `/usr/local/lib` on FreeBSD.
|
data/lib/mkmf/lite.rb
CHANGED
|
@@ -4,8 +4,8 @@ require 'erb'
|
|
|
4
4
|
require 'rbconfig'
|
|
5
5
|
require 'tmpdir'
|
|
6
6
|
require 'open3'
|
|
7
|
+
require 'shellwords'
|
|
7
8
|
require 'ptools'
|
|
8
|
-
require 'fileutils'
|
|
9
9
|
require 'memoist'
|
|
10
10
|
|
|
11
11
|
# The Mkmf module serves as a namespace only.
|
|
@@ -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.
|
|
19
|
+
MKMF_LITE_VERSION = '0.8.0'
|
|
20
20
|
|
|
21
21
|
private
|
|
22
22
|
|
|
@@ -51,24 +51,16 @@ module Mkmf
|
|
|
51
51
|
'conftest.c'
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def cpp_out_file
|
|
54
|
+
def cpp_out_file(output_file = 'conftest.exe')
|
|
55
55
|
if windows_with_cl_compiler?
|
|
56
|
-
|
|
56
|
+
"/Fe#{output_file}"
|
|
57
57
|
else
|
|
58
|
-
'-o
|
|
58
|
+
['-o', output_file]
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
memoize :cpp_out_file
|
|
63
|
-
|
|
64
62
|
def cpp_libraries
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if cpp_command.match?(/clang/i)
|
|
68
|
-
'-Lrt -Ldl -Lcrypt -Lm'
|
|
69
|
-
else
|
|
70
|
-
'-lrt -ldl -lcrypt -lm'
|
|
71
|
-
end
|
|
63
|
+
nil
|
|
72
64
|
end
|
|
73
65
|
|
|
74
66
|
memoize :cpp_libraries
|
|
@@ -84,7 +76,7 @@ module Mkmf
|
|
|
84
76
|
paths << '-L/usr/local/lib' if File.directory?('/usr/local/lib')
|
|
85
77
|
end
|
|
86
78
|
|
|
87
|
-
paths.empty? ? nil : paths
|
|
79
|
+
paths.empty? ? nil : paths
|
|
88
80
|
end
|
|
89
81
|
|
|
90
82
|
memoize :cpp_library_paths
|
|
@@ -241,35 +233,31 @@ module Mkmf
|
|
|
241
233
|
def build_directory_options(directories)
|
|
242
234
|
return nil if directories.empty?
|
|
243
235
|
|
|
244
|
-
directories.map { |dir| "-I#{dir}" }
|
|
236
|
+
directories.flatten.map { |dir| "-I#{dir}" }
|
|
245
237
|
end
|
|
246
238
|
|
|
247
|
-
def build_compile_command(command_options = nil, library_options = nil)
|
|
248
|
-
|
|
249
|
-
|
|
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
|
|
239
|
+
def build_compile_command(command_options = nil, library_options = nil, paths = {})
|
|
240
|
+
source_file = paths.fetch(:source_file, cpp_source_file)
|
|
241
|
+
output_file = paths.fetch(:output_file, 'conftest.exe')
|
|
259
242
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
243
|
+
command_parts = shellwords(cpp_command)
|
|
244
|
+
command_parts.concat(shellwords(command_options))
|
|
245
|
+
command_parts.concat(shellwords(cpp_library_paths))
|
|
246
|
+
command_parts.concat(shellwords(cpp_libraries))
|
|
247
|
+
command_parts.concat(shellwords(cpp_defs))
|
|
248
|
+
command_parts.concat(shellwords(cpp_out_file(output_file)))
|
|
249
|
+
command_parts << source_file
|
|
250
|
+
command_parts.concat(shellwords(library_options))
|
|
263
251
|
|
|
264
|
-
|
|
265
|
-
|
|
252
|
+
command_parts
|
|
253
|
+
end
|
|
266
254
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
255
|
+
def shellwords(options)
|
|
256
|
+
if options.is_a?(Array)
|
|
257
|
+
options.flatten.compact.map(&:to_s)
|
|
258
|
+
else
|
|
259
|
+
Shellwords.split(options.to_s)
|
|
260
|
+
end
|
|
273
261
|
end
|
|
274
262
|
|
|
275
263
|
# Take an array of header file names (or convert it to an array if it's a
|
|
@@ -303,56 +291,53 @@ module Mkmf
|
|
|
303
291
|
# The code generated is expected to print a number to STDOUT, which
|
|
304
292
|
# is then grabbed and returned as an integer.
|
|
305
293
|
#
|
|
306
|
-
# Note that $stderr is temporarily redirected to the null device because
|
|
307
|
-
# we don't actually care about the reason for failure, though a Ruby
|
|
308
|
-
# error is raised if the compilation step fails.
|
|
309
|
-
#
|
|
310
294
|
def try_to_execute(code, command_options = nil)
|
|
311
295
|
result = 0
|
|
312
296
|
|
|
313
|
-
Dir.
|
|
314
|
-
File.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
297
|
+
Dir.mktmpdir('mkmf-lite') do |dir|
|
|
298
|
+
source_file = File.join(dir, cpp_source_file)
|
|
299
|
+
output_file = File.join(dir, 'conftest.exe')
|
|
300
|
+
File.write(source_file, code)
|
|
301
|
+
command = build_compile_command(
|
|
302
|
+
command_options,
|
|
303
|
+
nil,
|
|
304
|
+
:source_file => source_file,
|
|
305
|
+
:output_file => output_file
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
_stdout, stderr, status = Open3.capture3(*command)
|
|
309
|
+
|
|
310
|
+
if status.success?
|
|
311
|
+
output, = Open3.capture2(output_file)
|
|
312
|
+
result = output.chomp.to_i
|
|
328
313
|
else
|
|
329
|
-
|
|
314
|
+
message = "Failed to compile source code with command '#{command.shelljoin}':\n#{stderr}===\n#{code}==="
|
|
315
|
+
raise StandardError, message
|
|
330
316
|
end
|
|
331
317
|
end
|
|
332
318
|
|
|
333
319
|
result
|
|
334
|
-
ensure
|
|
335
|
-
FileUtils.rm_f(File.join(Dir.tmpdir, cpp_source_file))
|
|
336
|
-
FileUtils.rm_f(File.join(Dir.tmpdir, 'conftest.exe'))
|
|
337
320
|
end
|
|
338
321
|
|
|
339
322
|
# Create a temporary bit of C source code in the temp directory, and
|
|
340
323
|
# try to compile it. If it succeeds, return true. Otherwise, return
|
|
341
324
|
# false.
|
|
342
325
|
#
|
|
343
|
-
# Note that $stderr is temporarily redirected to the null device because
|
|
344
|
-
# we don't actually care about the reason for failure.
|
|
345
|
-
#
|
|
346
326
|
def try_to_compile(code, command_options = nil, library_options = nil)
|
|
347
|
-
Dir.
|
|
348
|
-
File.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
327
|
+
Dir.mktmpdir('mkmf-lite') do |dir|
|
|
328
|
+
source_file = File.join(dir, cpp_source_file)
|
|
329
|
+
output_file = File.join(dir, 'conftest.exe')
|
|
330
|
+
File.write(source_file, code)
|
|
331
|
+
command = build_compile_command(
|
|
332
|
+
command_options,
|
|
333
|
+
library_options,
|
|
334
|
+
:source_file => source_file,
|
|
335
|
+
:output_file => output_file
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
_stdout, _stderr, status = Open3.capture3(*command)
|
|
339
|
+
status.success?
|
|
352
340
|
end
|
|
353
|
-
ensure
|
|
354
|
-
FileUtils.rm_f(File.join(Dir.tmpdir, cpp_source_file))
|
|
355
|
-
FileUtils.rm_f(File.join(Dir.tmpdir, 'conftest.exe'))
|
|
356
341
|
end
|
|
357
342
|
|
|
358
343
|
# Slurp the contents of the template file for evaluation later.
|
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.
|
|
6
|
+
spec.version = '0.8.0'
|
|
7
7
|
spec.author = 'Daniel J. Berger'
|
|
8
8
|
spec.license = 'Apache-2.0'
|
|
9
9
|
spec.email = 'djberg96@gmail.com'
|
data/spec/mkmf_lite_spec.rb
CHANGED
|
@@ -9,6 +9,7 @@ require 'rubygems'
|
|
|
9
9
|
require 'rspec'
|
|
10
10
|
require 'mkmf/lite'
|
|
11
11
|
require 'fileutils'
|
|
12
|
+
require 'tmpdir'
|
|
12
13
|
|
|
13
14
|
RSpec.describe Mkmf::Lite do
|
|
14
15
|
subject { Class.new{ |obj| obj.extend Mkmf::Lite } }
|
|
@@ -20,7 +21,7 @@ RSpec.describe Mkmf::Lite do
|
|
|
20
21
|
|
|
21
22
|
describe 'constants' do
|
|
22
23
|
example 'version information' do
|
|
23
|
-
expect(described_class::MKMF_LITE_VERSION).to eq('0.
|
|
24
|
+
expect(described_class::MKMF_LITE_VERSION).to eq('0.8.0')
|
|
24
25
|
expect(described_class::MKMF_LITE_VERSION).to be_frozen
|
|
25
26
|
end
|
|
26
27
|
end
|
|
@@ -39,6 +40,16 @@ RSpec.describe Mkmf::Lite do
|
|
|
39
40
|
expect{ subject.have_header('stdio.h', '/usr/local/include') }.not_to raise_error
|
|
40
41
|
expect{ subject.have_header('stdio.h', '/usr/local/include', '/usr/include') }.not_to raise_error
|
|
41
42
|
end
|
|
43
|
+
|
|
44
|
+
example 'have_header accepts a directory with spaces' do
|
|
45
|
+
Dir.mktmpdir('mkmf lite') do |dir|
|
|
46
|
+
header = 'mkmf_lite_space_header.h'
|
|
47
|
+
|
|
48
|
+
File.write(File.join(dir, header), "#define MKMF_LITE_SPACE_HEADER 1\n")
|
|
49
|
+
|
|
50
|
+
expect(subject.have_header(header, dir)).to be(true)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
42
53
|
end
|
|
43
54
|
|
|
44
55
|
context 'have_func' do
|
|
@@ -194,4 +205,29 @@ RSpec.describe Mkmf::Lite do
|
|
|
194
205
|
expect{ subject.have_library('m', 'sqrt', 'math.h', 'bogus') }.to raise_error(ArgumentError)
|
|
195
206
|
end
|
|
196
207
|
end
|
|
208
|
+
|
|
209
|
+
describe 'command construction' do
|
|
210
|
+
let(:command_with_spaces) do
|
|
211
|
+
subject.send(
|
|
212
|
+
:build_compile_command,
|
|
213
|
+
['-I/tmp/include dir'],
|
|
214
|
+
nil,
|
|
215
|
+
:source_file => 'source.c',
|
|
216
|
+
:output_file => 'output file'
|
|
217
|
+
)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
example 'build_compile_command returns argv-style command parts' do
|
|
221
|
+
expect(command_with_spaces).to include('-I/tmp/include dir')
|
|
222
|
+
expect(command_with_spaces).to include('source.c')
|
|
223
|
+
expect(command_with_spaces.any? { |part| part.include?('output file') }).to be(true)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
example 'build_compile_command does not include implicit Linux libraries' do
|
|
227
|
+
command = subject.send(:build_compile_command)
|
|
228
|
+
|
|
229
|
+
expect(command).not_to include('-Lrt', '-Ldl', '-Lcrypt', '-Lm')
|
|
230
|
+
expect(command).not_to include('-lrt', '-ldl', '-lcrypt', '-lm')
|
|
231
|
+
end
|
|
232
|
+
end
|
|
197
233
|
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.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel J. Berger
|
|
@@ -136,10 +136,9 @@ files:
|
|
|
136
136
|
- LICENSE
|
|
137
137
|
- MANIFEST.md
|
|
138
138
|
- README.md
|
|
139
|
+
- ROADMAP.md
|
|
139
140
|
- Rakefile
|
|
140
141
|
- certs/djberg96_pub.pem
|
|
141
|
-
- conftest.c
|
|
142
|
-
- conftest.exe
|
|
143
142
|
- lib/mkmf-lite.rb
|
|
144
143
|
- lib/mkmf/lite.rb
|
|
145
144
|
- lib/mkmf/templates/check_offsetof.erb
|
|
@@ -179,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
179
178
|
- !ruby/object:Gem::Version
|
|
180
179
|
version: '0'
|
|
181
180
|
requirements: []
|
|
182
|
-
rubygems_version:
|
|
181
|
+
rubygems_version: 4.0.12
|
|
183
182
|
specification_version: 4
|
|
184
183
|
summary: A lighter version of mkmf designed for use as a library
|
|
185
184
|
test_files:
|
metadata.gz.sig
CHANGED
|
Binary file
|
data/conftest.c
DELETED
data/conftest.exe
DELETED
|
Binary file
|