breaker_machines 0.7.0 → 0.9.2

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/ext/breaker_machines_native/ffi/extconf.rb +11 -16
  3. data/lib/breaker_machines/native_extension.rb +52 -15
  4. data/lib/breaker_machines/version.rb +1 -1
  5. metadata +14 -60
  6. data/ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/common.rs +0 -355
  7. data/ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/dynamic.rs +0 -276
  8. data/ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/macros.rs +0 -49
  9. data/ext/breaker_machines_native/target/debug/build/rb-sys-2bb7281aac8faec8/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +0 -8936
  10. data/ext/breaker_machines_native/target/debug/build/rb-sys-54cb99ea6aeab8bc/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +0 -8936
  11. data/ext/breaker_machines_native/target/debug/build/rb-sys-9e64a270c6421e93/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +0 -8936
  12. data/ext/breaker_machines_native/target/debug/build/rb-sys-e627030114d3fc19/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +0 -8936
  13. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/Cargo.toml +0 -48
  14. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/examples/basic.rs +0 -61
  15. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/builder.rs +0 -154
  16. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/callbacks.rs +0 -55
  17. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/circuit.rs +0 -607
  18. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/errors.rs +0 -38
  19. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/lib.rs +0 -58
  20. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/storage.rs +0 -377
  21. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/Cargo.toml +0 -48
  22. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/examples/basic.rs +0 -61
  23. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/builder.rs +0 -173
  24. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/callbacks.rs +0 -55
  25. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/circuit.rs +0 -855
  26. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/errors.rs +0 -38
  27. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/lib.rs +0 -58
  28. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/storage.rs +0 -377
  29. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/Cargo.toml +0 -48
  30. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/examples/basic.rs +0 -61
  31. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/builder.rs +0 -154
  32. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/callbacks.rs +0 -55
  33. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/circuit.rs +0 -607
  34. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/errors.rs +0 -38
  35. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/lib.rs +0 -58
  36. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/storage.rs +0 -377
  37. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/Cargo.toml +0 -48
  38. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/examples/basic.rs +0 -61
  39. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/builder.rs +0 -232
  40. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/bulkhead.rs +0 -223
  41. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/callbacks.rs +0 -58
  42. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/circuit.rs +0 -1156
  43. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/classifier.rs +0 -177
  44. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/errors.rs +0 -47
  45. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/lib.rs +0 -62
  46. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/storage.rs +0 -377
  47. data/ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/common.rs +0 -355
  48. data/ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/dynamic.rs +0 -276
  49. data/ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/macros.rs +0 -49
  50. data/ext/breaker_machines_native/target/release/build/rb-sys-064bf9961dd17810/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +0 -8936
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5137f3692641c76411b86e725df03e901220a09d18a9bc1ba64fc1834d93b811
4
- data.tar.gz: f5f0c05289c82dfe6aa1fe23322a531fbfd9faa1b8e9f29575eb5c801aacf712
3
+ metadata.gz: 2d890ea2732633801242760b868020a4ad4d517693a71a91767b27ce8cfde282
4
+ data.tar.gz: bb5a5b86d182b90cabdf0871d81f2b82ef58218e77613dc5f505067b6a39a63c
5
5
  SHA512:
6
- metadata.gz: 1150d77d3823b038277fb4bd7ee2c28bb39ea0307fefe227f2346c220ceb961f89349bfadc0d8b7bbcea01d7c0bd319ad96177c2de0eb24b6df82f57ee8001f6
7
- data.tar.gz: 3673de4be4d9784ea7135da34e0d02aae91c4b2f8a0c04bc3e058cb01e7f250feb9e6526c4f638d555cc7a3e35a4d3ffb75ffcd770db867442e234ecf43f58a7
6
+ metadata.gz: b84c67c557a067f768e9b16e73a0e5e9186e909d211632151b79a17558ac56c78d92a67fc9e86b90ef6fb6382eb2f00ab57dc984a7ff64d4e89291341155dbb5
7
+ data.tar.gz: a1e3853602dab814c12e3581939ba95060e0ded7b023c906833530418a3b5071e3af29083303be06e1f98cf4e96028b4e1a1a9657910e18a0e69543940e2b1c8
@@ -1,20 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Skip native extension compilation on JRuby
4
- if RUBY_ENGINE == 'jruby'
5
- puts 'Skipping native extension compilation on JRuby'
6
- puts 'BreakerMachines will use pure Ruby backend'
7
- makefile_content = "all:\n\t@echo 'Skipping native extension on JRuby'\n" \
8
- "install:\n\t@echo 'Skipping native extension on JRuby'\n"
9
- File.write('Makefile', makefile_content)
10
- exit 0
11
- end
12
-
13
- # Check if Cargo is available
14
- def cargo_available?
15
- system('cargo --version > /dev/null 2>&1')
16
- end
17
-
18
3
  def create_noop_makefile(message)
19
4
  warn message
20
5
  warn 'BreakerMachines will fall back to pure Ruby backend.'
@@ -27,6 +12,16 @@ def create_noop_makefile(message)
27
12
  exit 0
28
13
  end
29
14
 
15
+ # Skip native extension compilation on JRuby
16
+ if RUBY_ENGINE == 'jruby'
17
+ create_noop_makefile('Skipping native extension on JRuby')
18
+ end
19
+
20
+ # Check if Cargo is available
21
+ def cargo_available?
22
+ system('cargo --version > /dev/null 2>&1')
23
+ end
24
+
30
25
  unless cargo_available?
31
26
  create_noop_makefile('Skipping native extension (Cargo not found)')
32
27
  end
@@ -55,7 +50,7 @@ begin
55
50
  if File.exist?(makefile_path)
56
51
  manifest_path = File.expand_path(__dir__)
57
52
  contents = File.read(makefile_path)
58
- contents.gsub!(%r{^RB_SYS_CARGO_MANIFEST_DIR \?=.*$}, "RB_SYS_CARGO_MANIFEST_DIR ?= #{manifest_path}")
53
+ contents.gsub!(/^RB_SYS_CARGO_MANIFEST_DIR \?=.*$/, "RB_SYS_CARGO_MANIFEST_DIR ?= #{manifest_path}")
59
54
  File.write(makefile_path, contents)
60
55
  end
61
56
  rescue LoadError => e
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rbconfig'
4
+ require 'active_support/core_ext/object/blank'
5
+
3
6
  module BreakerMachines
4
7
  # Handles loading and status of the optional native extension
5
8
  module NativeExtension
@@ -9,29 +12,29 @@ module BreakerMachines
9
12
  def load!
10
13
  return @loaded if defined?(@loaded)
11
14
 
12
- # Respect explicit ENV flag to disable native (useful for testing)
13
- if ENV['BREAKER_MACHINES_NATIVE'] == '0'
15
+ # Native extension is opt-in: only load if explicitly enabled
16
+ unless ENV['BREAKER_MACHINES_NATIVE'] == '1'
14
17
  @loaded = false
15
18
  BreakerMachines.instance_variable_set(:@native_available, false)
16
- BreakerMachines.log(:info, 'Native extension disabled via ENV')
17
19
  return false
18
20
  end
19
21
 
20
- @loaded = true
21
- require 'breaker_machines_native/breaker_machines_native'
22
- BreakerMachines.instance_variable_set(:@native_available, true)
23
- BreakerMachines.log(:info, 'Native extension loaded successfully')
24
- true
25
- rescue LoadError => e
26
- @loaded = false
27
- BreakerMachines.instance_variable_set(:@native_available, false)
22
+ errors = []
28
23
 
29
- # Only log if it's not JRuby (expected failure) and logging is enabled
30
- if RUBY_ENGINE != 'jruby'
31
- BreakerMachines.log(:warn, "Native extension not available: #{e.message}")
32
- BreakerMachines.log(:warn, 'Using pure Ruby backend (slower but functional)')
24
+ native_library_candidates.each do |require_path|
25
+ try_require(require_path)
26
+ @loaded = true
27
+ BreakerMachines.instance_variable_set(:@native_available, true)
28
+ BreakerMachines.log(:info, "Native extension loaded successfully (#{require_path})")
29
+ return true
30
+ rescue LoadError => e
31
+ errors << "#{require_path}: #{e.message}"
33
32
  end
34
33
 
34
+ @loaded = false
35
+ BreakerMachines.instance_variable_set(:@native_available, false)
36
+ BreakerMachines.log(:warn, "Native extension not available: #{errors.join(' | ')}") unless errors.empty?
37
+
35
38
  false
36
39
  end
37
40
 
@@ -39,6 +42,40 @@ module BreakerMachines
39
42
  def loaded?
40
43
  defined?(@loaded) && @loaded
41
44
  end
45
+
46
+ private
47
+
48
+ def native_library_candidates
49
+ dlext = RbConfig::CONFIG['DLEXT']
50
+ base_dir = File.expand_path('../breaker_machines_native', __dir__)
51
+ ruby_version = RbConfig::CONFIG['ruby_version']
52
+ arch = RbConfig::CONFIG['arch']
53
+ platform = Gem::Platform.local.to_s
54
+
55
+ matches = Dir.glob(File.join(base_dir, '**', "breaker_machines_native.#{dlext}"))
56
+
57
+ prioritized = matches.sort_by do |path|
58
+ score = 0
59
+ score -= 3 if path.include?(ruby_version)
60
+ score -= 2 if path.include?(arch)
61
+ score -= 1 if path.include?(platform)
62
+ [score, path]
63
+ end
64
+
65
+ candidates = prioritized.map { |full_path| require_path_for(full_path, dlext) }.presence
66
+ candidates ||= ['breaker_machines_native/breaker_machines_native']
67
+ candidates.uniq
68
+ end
69
+
70
+ def require_path_for(full_path, dlext)
71
+ root = File.expand_path('..', __dir__)
72
+ relative = full_path.sub(%r{^#{Regexp.escape(root)}/?}, '')
73
+ relative.sub(/\.#{Regexp.escape(dlext)}\z/, '')
74
+ end
75
+
76
+ def try_require(require_path)
77
+ require require_path
78
+ end
42
79
  end
43
80
  end
44
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BreakerMachines
4
- VERSION = '0.7.0'
4
+ VERSION = '0.9.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breaker_machines
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdelkader Boudih
@@ -52,47 +52,47 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: '1.3'
54
54
  - !ruby/object:Gem::Dependency
55
- name: state_machines
55
+ name: rb_sys
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - ">="
58
+ - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 0.100.4
60
+ version: '0.9'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - ">="
65
+ - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 0.100.4
67
+ version: '0.9'
68
68
  - !ruby/object:Gem::Dependency
69
- name: zeitwerk
69
+ name: state_machines
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '2.7'
74
+ version: 0.100.4
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - "~>"
79
+ - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: '2.7'
81
+ version: 0.100.4
82
82
  - !ruby/object:Gem::Dependency
83
- name: rb_sys
83
+ name: zeitwerk
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '0.9'
88
+ version: '2.7'
89
89
  type: :runtime
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0.9'
95
+ version: '2.7'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: minitest
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -165,51 +165,6 @@ files:
165
165
  - ext/breaker_machines_native/ffi/Cargo.toml
166
166
  - ext/breaker_machines_native/ffi/extconf.rb
167
167
  - ext/breaker_machines_native/ffi/src/lib.rs
168
- - ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/common.rs
169
- - ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/dynamic.rs
170
- - ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/macros.rs
171
- - ext/breaker_machines_native/target/debug/build/rb-sys-2bb7281aac8faec8/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs
172
- - ext/breaker_machines_native/target/debug/build/rb-sys-54cb99ea6aeab8bc/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs
173
- - ext/breaker_machines_native/target/debug/build/rb-sys-9e64a270c6421e93/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs
174
- - ext/breaker_machines_native/target/debug/build/rb-sys-e627030114d3fc19/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs
175
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/Cargo.toml
176
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/examples/basic.rs
177
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/builder.rs
178
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/callbacks.rs
179
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/circuit.rs
180
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/errors.rs
181
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/lib.rs
182
- - ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/storage.rs
183
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/Cargo.toml
184
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/examples/basic.rs
185
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/builder.rs
186
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/callbacks.rs
187
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/circuit.rs
188
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/errors.rs
189
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/lib.rs
190
- - ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/storage.rs
191
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/Cargo.toml
192
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/examples/basic.rs
193
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/builder.rs
194
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/callbacks.rs
195
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/circuit.rs
196
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/errors.rs
197
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/lib.rs
198
- - ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/storage.rs
199
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/Cargo.toml
200
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/examples/basic.rs
201
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/builder.rs
202
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/bulkhead.rs
203
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/callbacks.rs
204
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/circuit.rs
205
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/classifier.rs
206
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/errors.rs
207
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/lib.rs
208
- - ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/storage.rs
209
- - ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/common.rs
210
- - ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/dynamic.rs
211
- - ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/macros.rs
212
- - ext/breaker_machines_native/target/release/build/rb-sys-064bf9961dd17810/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs
213
168
  - lib/breaker_machines.rb
214
169
  - lib/breaker_machines/async_circuit.rb
215
170
  - lib/breaker_machines/async_support.rb
@@ -266,7 +221,6 @@ homepage: https://github.com/seuros/breaker_machines
266
221
  licenses:
267
222
  - MIT
268
223
  metadata:
269
- allowed_push_host: https://rubygems.org
270
224
  homepage_uri: https://github.com/seuros/breaker_machines
271
225
  source_code_uri: https://github.com/seuros/breaker_machines
272
226
  bug_tracker_uri: https://github.com/seuros/breaker_machines/issues
@@ -1,355 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
-
3
- use std::cell::RefCell;
4
- use std::collections::HashMap;
5
- use std::env;
6
- use std::path::{Path, PathBuf};
7
- use std::process::Command;
8
-
9
- use glob::{MatchOptions, Pattern};
10
-
11
- //================================================
12
- // Commands
13
- //================================================
14
-
15
- thread_local! {
16
- /// The errors encountered by the build script while executing commands.
17
- static COMMAND_ERRORS: RefCell<HashMap<String, Vec<String>>> = RefCell::default();
18
- }
19
-
20
- /// Adds an error encountered by the build script while executing a command.
21
- fn add_command_error(name: &str, path: &str, arguments: &[&str], message: String) {
22
- COMMAND_ERRORS.with(|e| {
23
- e.borrow_mut()
24
- .entry(name.into())
25
- .or_default()
26
- .push(format!(
27
- "couldn't execute `{} {}` (path={}) ({})",
28
- name,
29
- arguments.join(" "),
30
- path,
31
- message,
32
- ))
33
- });
34
- }
35
-
36
- /// A struct that prints the errors encountered by the build script while
37
- /// executing commands when dropped (unless explictly discarded).
38
- ///
39
- /// This is handy because we only want to print these errors when the build
40
- /// script fails to link to an instance of `libclang`. For example, if
41
- /// `llvm-config` couldn't be executed but an instance of `libclang` was found
42
- /// anyway we don't want to pollute the build output with irrelevant errors.
43
- #[derive(Default)]
44
- pub struct CommandErrorPrinter {
45
- discard: bool,
46
- }
47
-
48
- impl CommandErrorPrinter {
49
- pub fn discard(mut self) {
50
- self.discard = true;
51
- }
52
- }
53
-
54
- impl Drop for CommandErrorPrinter {
55
- fn drop(&mut self) {
56
- if self.discard {
57
- return;
58
- }
59
-
60
- let errors = COMMAND_ERRORS.with(|e| e.borrow().clone());
61
-
62
- if let Some(errors) = errors.get("llvm-config") {
63
- println!(
64
- "cargo:warning=could not execute `llvm-config` one or more \
65
- times, if the LLVM_CONFIG_PATH environment variable is set to \
66
- a full path to valid `llvm-config` executable it will be used \
67
- to try to find an instance of `libclang` on your system: {}",
68
- errors
69
- .iter()
70
- .map(|e| format!("\"{}\"", e))
71
- .collect::<Vec<_>>()
72
- .join("\n "),
73
- )
74
- }
75
-
76
- if let Some(errors) = errors.get("xcode-select") {
77
- println!(
78
- "cargo:warning=could not execute `xcode-select` one or more \
79
- times, if a valid instance of this executable is on your PATH \
80
- it will be used to try to find an instance of `libclang` on \
81
- your system: {}",
82
- errors
83
- .iter()
84
- .map(|e| format!("\"{}\"", e))
85
- .collect::<Vec<_>>()
86
- .join("\n "),
87
- )
88
- }
89
- }
90
- }
91
-
92
- #[cfg(test)]
93
- lazy_static::lazy_static! {
94
- pub static ref RUN_COMMAND_MOCK: std::sync::Mutex<
95
- Option<Box<dyn Fn(&str, &str, &[&str]) -> Option<String> + Send + Sync + 'static>>,
96
- > = std::sync::Mutex::new(None);
97
- }
98
-
99
- /// Executes a command and returns the `stdout` output if the command was
100
- /// successfully executed (errors are added to `COMMAND_ERRORS`).
101
- fn run_command(name: &str, path: &str, arguments: &[&str]) -> Option<String> {
102
- #[cfg(test)]
103
- if let Some(command) = &*RUN_COMMAND_MOCK.lock().unwrap() {
104
- return command(name, path, arguments);
105
- }
106
-
107
- let output = match Command::new(path).args(arguments).output() {
108
- Ok(output) => output,
109
- Err(error) => {
110
- let message = format!("error: {}", error);
111
- add_command_error(name, path, arguments, message);
112
- return None;
113
- }
114
- };
115
-
116
- if output.status.success() {
117
- Some(String::from_utf8_lossy(&output.stdout).into_owned())
118
- } else {
119
- let message = format!("exit code: {}", output.status);
120
- add_command_error(name, path, arguments, message);
121
- None
122
- }
123
- }
124
-
125
- /// Executes the `llvm-config` command and returns the `stdout` output if the
126
- /// command was successfully executed (errors are added to `COMMAND_ERRORS`).
127
- pub fn run_llvm_config(arguments: &[&str]) -> Option<String> {
128
- let path = env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into());
129
- run_command("llvm-config", &path, arguments)
130
- }
131
-
132
- /// Executes the `xcode-select` command and returns the `stdout` output if the
133
- /// command was successfully executed (errors are added to `COMMAND_ERRORS`).
134
- pub fn run_xcode_select(arguments: &[&str]) -> Option<String> {
135
- run_command("xcode-select", "xcode-select", arguments)
136
- }
137
-
138
- //================================================
139
- // Search Directories
140
- //================================================
141
- // These search directories are listed in order of
142
- // preference, so if multiple `libclang` instances
143
- // are found when searching matching directories,
144
- // the `libclang` instances from earlier
145
- // directories will be preferred (though version
146
- // takes precedence over location).
147
- //================================================
148
-
149
- /// `libclang` directory patterns for Haiku.
150
- const DIRECTORIES_HAIKU: &[&str] = &[
151
- "/boot/home/config/non-packaged/develop/lib",
152
- "/boot/home/config/non-packaged/lib",
153
- "/boot/system/non-packaged/develop/lib",
154
- "/boot/system/non-packaged/lib",
155
- "/boot/system/develop/lib",
156
- "/boot/system/lib",
157
- ];
158
-
159
- /// `libclang` directory patterns for Linux (and FreeBSD).
160
- const DIRECTORIES_LINUX: &[&str] = &[
161
- "/usr/local/llvm*/lib*",
162
- "/usr/local/lib*/*/*",
163
- "/usr/local/lib*/*",
164
- "/usr/local/lib*",
165
- "/usr/lib*/*/*",
166
- "/usr/lib*/*",
167
- "/usr/lib*",
168
- ];
169
-
170
- /// `libclang` directory patterns for macOS.
171
- const DIRECTORIES_MACOS: &[&str] = &[
172
- "/usr/local/opt/llvm*/lib/llvm*/lib",
173
- "/Library/Developer/CommandLineTools/usr/lib",
174
- "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
175
- "/usr/local/opt/llvm*/lib",
176
- ];
177
-
178
- /// `libclang` directory patterns for Windows.
179
- ///
180
- /// The boolean indicates whether the directory pattern should be used when
181
- /// compiling for an MSVC target environment.
182
- const DIRECTORIES_WINDOWS: &[(&str, bool)] = &[
183
- // LLVM + Clang can be installed using Scoop (https://scoop.sh).
184
- // Other Windows package managers install LLVM + Clang to other listed
185
- // system-wide directories.
186
- ("C:\\Users\\*\\scoop\\apps\\llvm\\current\\lib", true),
187
- ("C:\\MSYS*\\MinGW*\\lib", false),
188
- ("C:\\Program Files*\\LLVM\\lib", true),
189
- ("C:\\LLVM\\lib", true),
190
- // LLVM + Clang can be installed as a component of Visual Studio.
191
- // https://github.com/KyleMayes/clang-sys/issues/121
192
- ("C:\\Program Files*\\Microsoft Visual Studio\\*\\VC\\Tools\\Llvm\\**\\lib", true),
193
- ];
194
-
195
- /// `libclang` directory patterns for illumos
196
- const DIRECTORIES_ILLUMOS: &[&str] = &[
197
- "/opt/ooce/llvm-*/lib",
198
- "/opt/ooce/clang-*/lib",
199
- ];
200
-
201
- //================================================
202
- // Searching
203
- //================================================
204
-
205
- /// Finds the files in a directory that match one or more filename glob patterns
206
- /// and returns the paths to and filenames of those files.
207
- fn search_directory(directory: &Path, filenames: &[String]) -> Vec<(PathBuf, String)> {
208
- // Escape the specified directory in case it contains characters that have
209
- // special meaning in glob patterns (e.g., `[` or `]`).
210
- let directory = Pattern::escape(directory.to_str().unwrap());
211
- let directory = Path::new(&directory);
212
-
213
- // Join the escaped directory to the filename glob patterns to obtain
214
- // complete glob patterns for the files being searched for.
215
- let paths = filenames
216
- .iter()
217
- .map(|f| directory.join(f).to_str().unwrap().to_owned());
218
-
219
- // Prevent wildcards from matching path separators to ensure that the search
220
- // is limited to the specified directory.
221
- let mut options = MatchOptions::new();
222
- options.require_literal_separator = true;
223
-
224
- paths
225
- .map(|p| glob::glob_with(&p, options))
226
- .filter_map(Result::ok)
227
- .flatten()
228
- .filter_map(|p| {
229
- let path = p.ok()?;
230
- let filename = path.file_name()?.to_str().unwrap();
231
-
232
- // The `libclang_shared` library has been renamed to `libclang-cpp`
233
- // in Clang 10. This can cause instances of this library (e.g.,
234
- // `libclang-cpp.so.10`) to be matched by patterns looking for
235
- // instances of `libclang`.
236
- if filename.contains("-cpp.") {
237
- return None;
238
- }
239
-
240
- Some((path.parent().unwrap().to_owned(), filename.into()))
241
- })
242
- .collect::<Vec<_>>()
243
- }
244
-
245
- /// Finds the files in a directory (and any relevant sibling directories) that
246
- /// match one or more filename glob patterns and returns the paths to and
247
- /// filenames of those files.
248
- fn search_directories(directory: &Path, filenames: &[String]) -> Vec<(PathBuf, String)> {
249
- let mut results = search_directory(directory, filenames);
250
-
251
- // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory
252
- // while `libclang.lib` is usually found in the LLVM `lib` directory. To
253
- // keep things consistent with other platforms, only LLVM `lib` directories
254
- // are included in the backup search directory globs so we need to search
255
- // the LLVM `bin` directory here.
256
- if target_os!("windows") && directory.ends_with("lib") {
257
- let sibling = directory.parent().unwrap().join("bin");
258
- results.extend(search_directory(&sibling, filenames));
259
- }
260
-
261
- results
262
- }
263
-
264
- /// Finds the `libclang` static or dynamic libraries matching one or more
265
- /// filename glob patterns and returns the paths to and filenames of those files.
266
- pub fn search_libclang_directories(filenames: &[String], variable: &str) -> Vec<(PathBuf, String)> {
267
- // Search only the path indicated by the relevant environment variable
268
- // (e.g., `LIBCLANG_PATH`) if it is set.
269
- if let Ok(path) = env::var(variable).map(|d| Path::new(&d).to_path_buf()) {
270
- // Check if the path is a matching file.
271
- if let Some(parent) = path.parent() {
272
- let filename = path.file_name().unwrap().to_str().unwrap();
273
- let libraries = search_directories(parent, filenames);
274
- if libraries.iter().any(|(_, f)| f == filename) {
275
- return vec![(parent.into(), filename.into())];
276
- }
277
- }
278
-
279
- // Check if the path is directory containing a matching file.
280
- return search_directories(&path, filenames);
281
- }
282
-
283
- let mut found = vec![];
284
-
285
- // Search the `bin` and `lib` directories in the directory returned by
286
- // `llvm-config --prefix`.
287
- if let Some(output) = run_llvm_config(&["--prefix"]) {
288
- let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
289
- found.extend(search_directories(&directory.join("bin"), filenames));
290
- found.extend(search_directories(&directory.join("lib"), filenames));
291
- found.extend(search_directories(&directory.join("lib64"), filenames));
292
- }
293
-
294
- // Search the toolchain directory in the directory returned by
295
- // `xcode-select --print-path`.
296
- if target_os!("macos") {
297
- if let Some(output) = run_xcode_select(&["--print-path"]) {
298
- let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
299
- let directory = directory.join("Toolchains/XcodeDefault.xctoolchain/usr/lib");
300
- found.extend(search_directories(&directory, filenames));
301
- }
302
- }
303
-
304
- // Search the directories in the `LD_LIBRARY_PATH` environment variable.
305
- if let Ok(path) = env::var("LD_LIBRARY_PATH") {
306
- for directory in env::split_paths(&path) {
307
- found.extend(search_directories(&directory, filenames));
308
- }
309
- }
310
-
311
- // Determine the `libclang` directory patterns.
312
- let directories: Vec<&str> = if target_os!("haiku") {
313
- DIRECTORIES_HAIKU.into()
314
- } else if target_os!("linux") || target_os!("freebsd") {
315
- DIRECTORIES_LINUX.into()
316
- } else if target_os!("macos") {
317
- DIRECTORIES_MACOS.into()
318
- } else if target_os!("windows") {
319
- let msvc = target_env!("msvc");
320
- DIRECTORIES_WINDOWS
321
- .iter()
322
- .filter(|d| d.1 || !msvc)
323
- .map(|d| d.0)
324
- .collect()
325
- } else if target_os!("illumos") {
326
- DIRECTORIES_ILLUMOS.into()
327
- } else {
328
- vec![]
329
- };
330
-
331
- // We use temporary directories when testing the build script so we'll
332
- // remove the prefixes that make the directories absolute.
333
- let directories = if test!() {
334
- directories
335
- .iter()
336
- .map(|d| d.strip_prefix('/').or_else(|| d.strip_prefix("C:\\")).unwrap_or(d))
337
- .collect::<Vec<_>>()
338
- } else {
339
- directories
340
- };
341
-
342
- // Search the directories provided by the `libclang` directory patterns.
343
- let mut options = MatchOptions::new();
344
- options.case_sensitive = false;
345
- options.require_literal_separator = true;
346
- for directory in directories.iter() {
347
- if let Ok(directories) = glob::glob_with(directory, options) {
348
- for directory in directories.filter_map(Result::ok).filter(|p| p.is_dir()) {
349
- found.extend(search_directories(&directory, filenames));
350
- }
351
- }
352
- }
353
-
354
- found
355
- }