rdkit_chem 2025.09.3.11 → 2025.09.3.12
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
- data/CMakeLists.txt +3 -3
- data/Code/RubyWrappers/Dict.i +1 -0
- data/Code/RubyWrappers/MolOps.i +10 -7
- data/Code/RubyWrappers/ROMol.i +16 -12
- data/Code/RubyWrappers/RWMol.i +21 -0
- data/Code/RubyWrappers/gmwrapper/CMakeLists.txt +6 -0
- data/Code/RubyWrappers/gmwrapper/GraphMolRuby.i +1 -0
- data/Code/RubyWrappers/point.i +0 -2
- data/README.md +92 -0
- data/Rakefile +102 -16
- data/ext/rdkit_chem/extconf.rb +32 -13
- data/lib/rdkit_chem/version.rb +4 -2
- data/test/test_rdkit_chem.rb +27 -12
- metadata +6 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8fd525bf8f5e07e8759d0f36c18ecabdf2ec3147a0d6bd240dd5c951fd629285
|
|
4
|
+
data.tar.gz: fa0cb66768fa9160dc781a6b374bfb4dc12abfa946f24daae07e851b5eb83346
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e99aee43550767d548a3534e56609ad84607d7c88d1ef59943b8b6bd329837cc2fef2e8c660ddf8519d1bea43ee2705c6f8fc626fae528ed0604c58bd8a189d8
|
|
7
|
+
data.tar.gz: adb78e57d89a631ff08f393bea2f26b356e181e7d52c2f46f7d628d80a1657cc3af2e1ab8d5de893be4f92cec01293bf83114c520075c9d73977854ff28621cc
|
data/CMakeLists.txt
CHANGED
|
@@ -78,7 +78,7 @@ option(RDK_BUILD_MINIMAL_LIB_MCS "build support for MCS into MinimalLib" OFF )
|
|
|
78
78
|
option(RDK_BUILD_MINIMAL_LIB_MOLZIP "build support for molzip into MinimalLib" OFF )
|
|
79
79
|
option(RDK_BUILD_LONG_RUNNING_TESTS "build longer running tests" OFF )
|
|
80
80
|
|
|
81
|
-
set(RDK_BOOST_VERSION "1.
|
|
81
|
+
set(RDK_BOOST_VERSION "1.81.0")
|
|
82
82
|
|
|
83
83
|
if(NOT MSVC)
|
|
84
84
|
if(RDK_OPTIMIZE_POPCNT)
|
|
@@ -226,9 +226,9 @@ if(RDK_BUILD_RPATH_SUPPORT)
|
|
|
226
226
|
ENDIF("${isSystemDir}" STREQUAL "-1")
|
|
227
227
|
endif()
|
|
228
228
|
|
|
229
|
-
if(
|
|
229
|
+
if(RDK_BUILD_SWIG_RUBY_WRAPPERS)
|
|
230
230
|
set(RDKit_RubyLibDir "${RDKit_ExternalDir}/ruby_lib")
|
|
231
|
-
endif(
|
|
231
|
+
endif(RDK_BUILD_SWIG_RUBY_WRAPPERS)
|
|
232
232
|
|
|
233
233
|
if(RDK_BUILD_COORDGEN_SUPPORT)
|
|
234
234
|
add_definitions(-DRDK_BUILD_COORDGEN_SUPPORT)
|
data/Code/RubyWrappers/Dict.i
CHANGED
data/Code/RubyWrappers/MolOps.i
CHANGED
|
@@ -44,24 +44,27 @@
|
|
|
44
44
|
%newobject RDKit::MolOps::mergeQueryHs;
|
|
45
45
|
%newobject RDKit::MolOps::adjustQueryProperties;
|
|
46
46
|
|
|
47
|
+
// IMPORTANT: %ignore must come BEFORE %include
|
|
48
|
+
// Ignore all sanitizeMol overloads - we provide custom wrapper below
|
|
49
|
+
%ignore RDKit::MolOps::sanitizeMol;
|
|
47
50
|
%ignore RDKit::MolOps::detectChemistryProblems;
|
|
48
51
|
%include <GraphMol/MolOps.h>
|
|
49
|
-
// Ignore only the 3-arg overload that uses reference parameters (incompatible with SWIG)
|
|
50
|
-
// This keeps the 1-arg sanitizeMol(RWMol &) available from the header
|
|
51
|
-
%ignore RDKit::MolOps::sanitizeMol(RWMol &,unsigned int &,unsigned int &);
|
|
52
52
|
%template(BoolPair) std::pair<bool, bool>;
|
|
53
53
|
|
|
54
54
|
%inline %{
|
|
55
|
-
|
|
55
|
+
// Custom sanitizeMol wrapper that returns the operation that failed
|
|
56
|
+
// Only ONE definition needed - default parameter handles both use cases
|
|
57
|
+
int sanitizeMol(RDKit::RWMol &mol, int sanitizeOps=RDKit::MolOps::SANITIZE_ALL){
|
|
56
58
|
unsigned int opThatFailed;
|
|
57
|
-
try{
|
|
58
|
-
RDKit::MolOps::sanitizeMol(mol,opThatFailed,
|
|
59
|
+
try {
|
|
60
|
+
RDKit::MolOps::sanitizeMol(mol, opThatFailed,
|
|
59
61
|
static_cast<unsigned int>(sanitizeOps));
|
|
60
62
|
} catch(...) {
|
|
61
63
|
|
|
62
64
|
}
|
|
63
65
|
return static_cast<int>(opThatFailed);
|
|
64
|
-
}
|
|
66
|
+
}
|
|
67
|
+
|
|
65
68
|
std::vector<boost::shared_ptr<RDKit::MolSanitizeException>> detectChemistryProblems(RDKit::ROMol &mol,int sanitizeOps=RDKit::MolOps::SANITIZE_ALL){
|
|
66
69
|
std::vector<boost::shared_ptr<RDKit::MolSanitizeException>> res;
|
|
67
70
|
auto probs = RDKit::MolOps::detectChemistryProblems(mol,sanitizeOps);
|
data/Code/RubyWrappers/ROMol.i
CHANGED
|
@@ -101,12 +101,11 @@
|
|
|
101
101
|
|
|
102
102
|
/*
|
|
103
103
|
* Special handling for Conformer objects which should not be GCed until the molecule is destroyed
|
|
104
|
-
* We
|
|
105
|
-
*
|
|
106
|
-
*
|
|
104
|
+
* We ignore the original addConformer and provide our own in %extend that copies the conformer
|
|
105
|
+
* to avoid double-free issues with shared_ptr wrappers.
|
|
106
|
+
* Both addConf and addConformer are defined in %extend below (add_conf and add_conformer in Ruby).
|
|
107
107
|
*/
|
|
108
|
-
%ignore addConformer
|
|
109
|
-
%rename(addConformer) RDKit::ROMol::addConf;
|
|
108
|
+
%ignore RDKit::ROMol::addConformer;
|
|
110
109
|
%include <GraphMol/ROMol.h>
|
|
111
110
|
|
|
112
111
|
%ignore SubstructMatch;
|
|
@@ -189,14 +188,19 @@ unsigned int getDefaultPickleProperties();
|
|
|
189
188
|
return res;
|
|
190
189
|
}
|
|
191
190
|
|
|
192
|
-
/*
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return self->addConformer(
|
|
191
|
+
/* Create a copy of the conformer before adding it to the molecule.
|
|
192
|
+
This avoids the double-free issue since Ruby owns the original and C++ owns the copy.
|
|
193
|
+
The original DISOWN approach doesn't work with shared_ptr wrappers. */
|
|
194
|
+
unsigned int addConf(RDKit::Conformer *conf, bool assignId=false) {
|
|
195
|
+
RDKit::Conformer *confCopy = new RDKit::Conformer(*conf);
|
|
196
|
+
return self->addConformer(confCopy, assignId);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Alias for addConf - exposes as add_conformer in Ruby
|
|
200
|
+
unsigned int addConformer(RDKit::Conformer *conf, bool assignId=false) {
|
|
201
|
+
RDKit::Conformer *confCopy = new RDKit::Conformer(*conf);
|
|
202
|
+
return self->addConformer(confCopy, assignId);
|
|
198
203
|
}
|
|
199
|
-
%clear RDKit::Conformer *ownedConf;
|
|
200
204
|
|
|
201
205
|
std::string MolToSmiles(bool doIsomericSmiles=true, bool doKekule=false, int rootedAtAtom=-1, bool canonical=true,
|
|
202
206
|
bool allBondsExplicit=false, bool allHsExplicit=false, bool doRandom=false) {
|
data/Code/RubyWrappers/RWMol.i
CHANGED
|
@@ -44,6 +44,13 @@
|
|
|
44
44
|
|
|
45
45
|
%template(RWMol_Vect) std::vector< boost::shared_ptr<RDKit::RWMol> >;
|
|
46
46
|
|
|
47
|
+
/*
|
|
48
|
+
* Special handling for Conformer objects which should not be GCed until the molecule is destroyed
|
|
49
|
+
* We ignore the original addConformer and provide our own in %extend that copies the conformer
|
|
50
|
+
* to avoid double-free issues with shared_ptr wrappers.
|
|
51
|
+
*/
|
|
52
|
+
%ignore RDKit::RWMol::addConformer;
|
|
53
|
+
|
|
47
54
|
// ignore the methods that allow the molecule to take ownership of atoms/Bonds
|
|
48
55
|
// (instead of copying them). This just leads to memory problems with Ruby
|
|
49
56
|
%ignore RDKit::RWMol::addAtom(Atom *atom,bool updateLabel,bool takeOwnership);
|
|
@@ -78,6 +85,20 @@
|
|
|
78
85
|
%include <GraphMol/RWMol.h>
|
|
79
86
|
|
|
80
87
|
%extend RDKit::RWMol {
|
|
88
|
+
/* Create a copy of the conformer before adding it to the molecule.
|
|
89
|
+
This avoids the double-free issue since Ruby owns the original and C++ owns the copy.
|
|
90
|
+
The original DISOWN approach doesn't work with shared_ptr wrappers. */
|
|
91
|
+
unsigned int addConf(RDKit::Conformer *conf, bool assignId=false) {
|
|
92
|
+
RDKit::Conformer *confCopy = new RDKit::Conformer(*conf);
|
|
93
|
+
return self->addConformer(confCopy, assignId);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Alias for addConf - exposes as add_conformer in Ruby
|
|
97
|
+
unsigned int addConformer(RDKit::Conformer *conf, bool assignId=false) {
|
|
98
|
+
RDKit::Conformer *confCopy = new RDKit::Conformer(*conf);
|
|
99
|
+
return self->addConformer(confCopy, assignId);
|
|
100
|
+
}
|
|
101
|
+
|
|
81
102
|
static RDKit::RWMOL_SPTR MolFromSmiles(const std::string &smi,int debugParse=0,bool sanitize=1,
|
|
82
103
|
std::map<std::string,std::string> *replacements=0){
|
|
83
104
|
return RDKit::RWMOL_SPTR(RDKit::SmilesToMol(smi, debugParse, sanitize,replacements));
|
|
@@ -55,6 +55,12 @@ SET(CMAKE_SWIG_FLAGS -small -naturalvar -autorename)
|
|
|
55
55
|
|
|
56
56
|
SWIG_ADD_LIBRARY(RDKitChem TYPE MODULE LANGUAGE ruby SOURCES GraphMolRuby.i)
|
|
57
57
|
|
|
58
|
+
if(APPLE)
|
|
59
|
+
set_target_properties(RDKitChem PROPERTIES
|
|
60
|
+
LINK_FLAGS "-undefined dynamic_lookup"
|
|
61
|
+
SUFFIX ".bundle")
|
|
62
|
+
endif()
|
|
63
|
+
|
|
58
64
|
# it doesnt seem like the threading libs should need to be here, but
|
|
59
65
|
# as of Oct 2012 using boost 1.51 under at least ubuntu 12.04 we get a
|
|
60
66
|
# link error if they aren't there.
|
data/Code/RubyWrappers/point.i
CHANGED
data/README.md
CHANGED
|
@@ -22,3 +22,95 @@ GEM for [RDKIT](http://rdkit.org/), an Open-Source Cheminformatics Software
|
|
|
22
22
|
It downloads the sources, compiles and installs RDKIT with the ruby bindings.
|
|
23
23
|
The installation may last very long - please be patient.
|
|
24
24
|
|
|
25
|
+
## macOS Build Notes
|
|
26
|
+
|
|
27
|
+
### Known Issues and Solutions
|
|
28
|
+
|
|
29
|
+
#### 1. Boost Serialization Not Found
|
|
30
|
+
|
|
31
|
+
**Error:**
|
|
32
|
+
```
|
|
33
|
+
CMake Error: Found package configuration file boost_serialization-config.cmake
|
|
34
|
+
but it set boost_serialization_FOUND to FALSE
|
|
35
|
+
Reason: No suitable build variant has been found.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Solution:** The gem has been updated to use static Boost flags (`-DBoost_USE_STATIC_LIBS=ON -DBoost_USE_STATIC_RUNTIME=ON`).
|
|
39
|
+
|
|
40
|
+
#### 2. Ruby Symbol Linking Error
|
|
41
|
+
|
|
42
|
+
**Error:**
|
|
43
|
+
```
|
|
44
|
+
Undefined symbols for architecture x86_64:
|
|
45
|
+
"_rb_define_class", "_rb_str_new", ... (Ruby C API symbols)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Solution:** Fixed in `Code/RubyWrappers/gmwrapper/CMakeLists.txt` with `-undefined dynamic_lookup` for macOS.
|
|
49
|
+
|
|
50
|
+
#### 3. Ruby 3.2+ Compatibility (CRITICAL)
|
|
51
|
+
|
|
52
|
+
**Error:**
|
|
53
|
+
```ruby
|
|
54
|
+
require 'RDKitChem'
|
|
55
|
+
# => TypeError: wrong argument type nil (expected Data)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Cause:** Ruby 3.2+ introduced a new `Data` class that conflicts with SWIG's wrapper generation.
|
|
59
|
+
|
|
60
|
+
**Workaround:** Use Ruby 3.1.x:
|
|
61
|
+
```bash
|
|
62
|
+
# Using asdf
|
|
63
|
+
asdf install ruby 3.1.6
|
|
64
|
+
asdf set ruby 3.1.6
|
|
65
|
+
|
|
66
|
+
# Using rbenv
|
|
67
|
+
rbenv install 3.1.6
|
|
68
|
+
rbenv local 3.1.6
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### 4. GitHub Actions CI - Xcode SDK Header Conflict
|
|
72
|
+
|
|
73
|
+
**Error:**
|
|
74
|
+
```
|
|
75
|
+
error: ISO C++17 does not allow 'register' storage class specifier [-Wregister]
|
|
76
|
+
error: no member named 'finite' in namespace 'std::__math'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Cause:** CMake finds Xcode SDK Ruby headers instead of `ruby/setup-ruby` installed headers.
|
|
80
|
+
|
|
81
|
+
**Solution:** Fixed in `extconf.rb` by explicitly passing Ruby paths to CMake.
|
|
82
|
+
|
|
83
|
+
### Ruby Version Compatibility
|
|
84
|
+
|
|
85
|
+
| Ruby Version | Build | Runtime | Notes |
|
|
86
|
+
|--------------|-------|---------|-------|
|
|
87
|
+
| 3.4.x | OK | FAIL | `Data` class conflict |
|
|
88
|
+
| 3.3.x | OK | FAIL | `Data` class conflict |
|
|
89
|
+
| 3.2.x | OK | FAIL | `Data` class conflict |
|
|
90
|
+
| 3.1.x | OK | OK | Recommended |
|
|
91
|
+
|
|
92
|
+
### Build Commands (macOS)
|
|
93
|
+
|
|
94
|
+
**Full Clean Build:**
|
|
95
|
+
```bash
|
|
96
|
+
rm -rf rdkit/build rdkit_chem
|
|
97
|
+
ruby ext/rdkit_chem/extconf.rb
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Resume Interrupted Build:**
|
|
101
|
+
```bash
|
|
102
|
+
cd rdkit/build
|
|
103
|
+
make -j8
|
|
104
|
+
make install
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Test Loading:**
|
|
108
|
+
```bash
|
|
109
|
+
DYLD_LIBRARY_PATH=$PWD/rdkit_chem/lib ruby -I $PWD/rdkit_chem/lib -e 'require "RDKitChem"; puts "Success!"'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Additional Notes
|
|
113
|
+
|
|
114
|
+
- Full build takes ~20 minutes
|
|
115
|
+
- Some `BOOST_NO_CXX98_FUNCTION_BASE` warnings during build are harmless
|
|
116
|
+
- For detailed troubleshooting, see [MACOS_BUILD_NOTES.md](MACOS_BUILD_NOTES.md)
|
data/Rakefile
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'rake/testtask'
|
|
4
4
|
require 'fileutils'
|
|
5
|
+
require 'set'
|
|
5
6
|
|
|
6
7
|
# Load version
|
|
7
8
|
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
|
@@ -29,12 +30,14 @@ task :build do
|
|
|
29
30
|
sh 'gem build rdkit_chem.gemspec'
|
|
30
31
|
end
|
|
31
32
|
|
|
32
|
-
desc 'Build pre-compiled gem for current platform
|
|
33
|
+
desc 'Build pre-compiled gem for current platform'
|
|
33
34
|
task :build_native do
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
ext_so = File.join(NATIVE_DIR, 'RDKitChem.so')
|
|
36
|
+
ext_bundle = File.join(NATIVE_DIR, 'RDKitChem.bundle')
|
|
37
|
+
|
|
38
|
+
unless File.exist?(ext_so) || File.exist?(ext_bundle)
|
|
39
|
+
abort "ERROR: Native extension not found at #{NATIVE_DIR}/RDKitChem.{so,bundle}\n" \
|
|
40
|
+
"Run 'cd ext/rdkit_chem && ruby extconf.rb' first to compile."
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
# Get Ruby version for directory structure
|
|
@@ -47,21 +50,28 @@ task :build_native do
|
|
|
47
50
|
FileUtils.mkdir_p(target_dir)
|
|
48
51
|
|
|
49
52
|
# Copy native extension and all shared libraries
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
# Linux: *.so*, macOS: *.bundle and *.dylib
|
|
54
|
+
lib_patterns = ["#{NATIVE_DIR}/*.so*", "#{NATIVE_DIR}/*.bundle", "#{NATIVE_DIR}/*.dylib"]
|
|
55
|
+
|
|
56
|
+
lib_patterns.each do |pattern|
|
|
57
|
+
Dir.glob(pattern).each do |lib|
|
|
58
|
+
# Skip symlinks first pass, copy only real files
|
|
59
|
+
next if File.symlink?(lib)
|
|
60
|
+
dest = File.join(target_dir, File.basename(lib))
|
|
61
|
+
FileUtils.cp(lib, dest, verbose: true)
|
|
62
|
+
end
|
|
55
63
|
end
|
|
56
64
|
|
|
57
65
|
# Also copy symlinks (they're needed for library resolution)
|
|
58
66
|
# This includes both .so -> .so.1 and .so.1 -> .so.1.version symlinks
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
lib_patterns.each do |pattern|
|
|
68
|
+
Dir.glob(pattern).each do |lib|
|
|
69
|
+
next unless File.symlink?(lib)
|
|
70
|
+
link_target = File.readlink(lib)
|
|
71
|
+
dest = File.join(target_dir, File.basename(lib))
|
|
72
|
+
FileUtils.rm_f(dest)
|
|
73
|
+
FileUtils.ln_s(link_target, dest, verbose: true)
|
|
74
|
+
end
|
|
65
75
|
end
|
|
66
76
|
|
|
67
77
|
# Build the platform-specific gem
|
|
@@ -137,6 +147,82 @@ task :fix_rpath do
|
|
|
137
147
|
sh "readelf -d #{so_file} | grep -E '(RPATH|RUNPATH)' || echo 'No RPATH found'"
|
|
138
148
|
end
|
|
139
149
|
|
|
150
|
+
desc 'Repair: bundle system libraries and fix RPATH'
|
|
151
|
+
task :repair do
|
|
152
|
+
Rake::Task['bundle_system_libs'].invoke
|
|
153
|
+
Rake::Task['fix_rpath'].invoke
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
MACOS_SYSTEM_LIBRARY_PREFIXES = ['/usr/lib/', '/System/'].freeze
|
|
157
|
+
MACOS_DEFAULT_SEARCH_PATHS = ['/opt/homebrew/lib', '/usr/local/lib'].freeze
|
|
158
|
+
|
|
159
|
+
def macos_shared_libraries(libs_dir)
|
|
160
|
+
Dir.glob("#{libs_dir}/*.dylib") + Dir.glob("#{libs_dir}/*.bundle")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def macos_dependencies(lib)
|
|
164
|
+
otool_output = `otool -L '#{lib}' 2>/dev/null`
|
|
165
|
+
otool_output.lines.drop(1).map { |line| line.strip.split(' ').first }.compact
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def macos_system_library?(path)
|
|
169
|
+
MACOS_SYSTEM_LIBRARY_PREFIXES.any? { |prefix| path.start_with?(prefix) }
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def macos_resolve_dependency(dep, libs_dir)
|
|
173
|
+
return dep if dep.start_with?('/') && File.exist?(dep)
|
|
174
|
+
|
|
175
|
+
basename = File.basename(dep)
|
|
176
|
+
candidates = [File.join(libs_dir, basename)] +
|
|
177
|
+
MACOS_DEFAULT_SEARCH_PATHS.map { |dir| File.join(dir, basename) }
|
|
178
|
+
candidates.find { |path| File.exist?(path) }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
desc 'Repair for macOS (bundle deps and fix install names)'
|
|
182
|
+
task :repair_macos do
|
|
183
|
+
libs_dir = File.expand_path(NATIVE_DIR)
|
|
184
|
+
libs = macos_shared_libraries(libs_dir)
|
|
185
|
+
abort "ERROR: no macOS libraries found in #{libs_dir}" if libs.empty?
|
|
186
|
+
|
|
187
|
+
queue = libs.dup
|
|
188
|
+
processed = Set.new
|
|
189
|
+
copied = 0
|
|
190
|
+
|
|
191
|
+
until queue.empty?
|
|
192
|
+
lib = queue.shift
|
|
193
|
+
next if processed.include?(lib)
|
|
194
|
+
processed.add(lib)
|
|
195
|
+
|
|
196
|
+
macos_dependencies(lib).each do |dep|
|
|
197
|
+
next if macos_system_library?(dep)
|
|
198
|
+
|
|
199
|
+
dep_path = macos_resolve_dependency(dep, libs_dir)
|
|
200
|
+
next if dep_path.nil?
|
|
201
|
+
|
|
202
|
+
dest = File.join(libs_dir, File.basename(dep_path))
|
|
203
|
+
unless File.exist?(dest)
|
|
204
|
+
FileUtils.cp(dep_path, dest, verbose: true)
|
|
205
|
+
copied += 1
|
|
206
|
+
end
|
|
207
|
+
queue << dest if File.exist?(dest)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
macos_shared_libraries(libs_dir).each do |lib|
|
|
212
|
+
lib_name = File.basename(lib)
|
|
213
|
+
system("install_name_tool -id @loader_path/#{lib_name} '#{lib}' 2>/dev/null") if lib.end_with?('.dylib')
|
|
214
|
+
|
|
215
|
+
macos_dependencies(lib).each do |dep|
|
|
216
|
+
next if macos_system_library?(dep)
|
|
217
|
+
|
|
218
|
+
dep_basename = File.basename(dep)
|
|
219
|
+
system("install_name_tool -change '#{dep}' '@loader_path/#{dep_basename}' '#{lib}' 2>/dev/null")
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
puts "Bundled #{copied} macOS dependencies."
|
|
224
|
+
end
|
|
225
|
+
|
|
140
226
|
desc 'Test that native extension loads without LD_LIBRARY_PATH'
|
|
141
227
|
task :test_native do
|
|
142
228
|
so_dir = File.expand_path(NATIVE_DIR, __dir__)
|
data/ext/rdkit_chem/extconf.rb
CHANGED
|
@@ -16,17 +16,20 @@ rescue StandardError
|
|
|
16
16
|
nr_processors = 1
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
def run_command(command, description)
|
|
20
|
+
puts description if description
|
|
21
|
+
success = system(command)
|
|
22
|
+
abort "ERROR: #{description || command} failed" unless success
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
FileUtils.mkdir_p rdkit_dir
|
|
20
26
|
Dir.chdir main_dir do
|
|
21
27
|
FileUtils.rm_rf src_dir
|
|
22
|
-
|
|
23
|
-
git = 'git clone https://github.com/rdkit/rdkit.git'
|
|
24
|
-
system git
|
|
28
|
+
run_command('git clone https://github.com/rdkit/rdkit.git', 'Downloading RDKit sources')
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
Dir.chdir(src_dir) do
|
|
28
|
-
|
|
29
|
-
system checkout
|
|
32
|
+
run_command('git checkout c2e48f41d88ddc15c6e1f818d1c4ced70b7f20d1', 'Checking out RDKit sources')
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
FileUtils.cp_r(
|
|
@@ -46,6 +49,26 @@ is_linux = host_os =~ /linux/
|
|
|
46
49
|
is_mac = host_os =~ /darwin/
|
|
47
50
|
ld_path = ''
|
|
48
51
|
|
|
52
|
+
# macOS-specific compiler flags to fix Ruby header compatibility issues
|
|
53
|
+
extra_cmake_flags = ''
|
|
54
|
+
if is_mac
|
|
55
|
+
# -Wno-register: Ruby headers use deprecated 'register' keyword (removed in C++17)
|
|
56
|
+
# -DHAVE_ISFINITE=1: Prevents Ruby's finite() from conflicting with std::isfinite
|
|
57
|
+
cxx_flags = '-std=c++17 -stdlib=libc++ -Wno-register -DHAVE_ISFINITE=1'
|
|
58
|
+
extra_cmake_flags = " -DCMAKE_CXX_FLAGS='#{cxx_flags}'"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Explicitly specify Ruby paths to avoid CMake finding system Ruby headers
|
|
62
|
+
# This is critical on macOS where Xcode SDK contains incompatible Ruby headers
|
|
63
|
+
ruby_executable = RbConfig.ruby
|
|
64
|
+
ruby_include_dir = RbConfig::CONFIG['rubyhdrdir']
|
|
65
|
+
ruby_arch_include_dir = RbConfig::CONFIG['rubyarchhdrdir']
|
|
66
|
+
|
|
67
|
+
extra_cmake_flags += " -DRuby_EXECUTABLE=#{ruby_executable}"
|
|
68
|
+
extra_cmake_flags += " -DRuby_INCLUDE_DIR=#{ruby_include_dir}"
|
|
69
|
+
extra_cmake_flags += " -DRuby_CONFIG_INCLUDE_DIR=#{ruby_arch_include_dir}" if ruby_arch_include_dir
|
|
70
|
+
extra_cmake_flags += " -DCMAKE_IGNORE_PREFIX_PATH='/Applications/Xcode.app;/Applications/Xcode_*.app'" if is_mac
|
|
71
|
+
|
|
49
72
|
if is_linux || is_mac
|
|
50
73
|
ld_string = is_linux ? 'LD_LIBRARY_PATH' : 'DYLD_LIBRARY_PATH'
|
|
51
74
|
ld_path = "#{ld_string}=#{install_dir}/lib"
|
|
@@ -56,22 +79,18 @@ end
|
|
|
56
79
|
|
|
57
80
|
FileUtils.mkdir_p build_dir
|
|
58
81
|
Dir.chdir build_dir do
|
|
59
|
-
puts 'Configuring RDKit'
|
|
60
|
-
|
|
61
82
|
cmake = "#{ld_path} cmake #{src_dir} -DRDK_INSTALL_INTREE=OFF " \
|
|
62
83
|
"-DCMAKE_INSTALL_PREFIX=#{install_dir} " \
|
|
63
84
|
'-DCMAKE_BUILD_TYPE=Release -DRDK_BUILD_PYTHON_WRAPPERS=OFF ' \
|
|
64
85
|
'-DRDK_BUILD_SWIG_WRAPPERS=ON -DRDK_BUILD_INCHI_SUPPORT=OFF ' \
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
system cmake
|
|
86
|
+
"-DBoost_NO_BOOST_CMAKE=ON -DRDK_USE_BOOST_IOSTREAMS=OFF#{extra_cmake_flags}"
|
|
87
|
+
run_command(cmake, 'Configuring RDKit')
|
|
68
88
|
end
|
|
69
89
|
|
|
70
90
|
# local installation in gem directory
|
|
71
91
|
Dir.chdir build_dir do
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
system "#{ld_path} make install"
|
|
92
|
+
run_command("#{ld_path} make -j#{nr_processors}", 'Compiling RDKit sources')
|
|
93
|
+
run_command("#{ld_path} make install", 'Installing RDKit sources')
|
|
75
94
|
end
|
|
76
95
|
|
|
77
96
|
# Remove compiled file, free spaces
|
data/lib/rdkit_chem/version.rb
CHANGED
data/test/test_rdkit_chem.rb
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test/unit"
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "rdkit_chem"
|
|
4
4
|
|
|
5
5
|
class RDKitTest < Test::Unit::TestCase
|
|
6
6
|
def test_mol_from_smiles
|
|
7
|
-
smiles =
|
|
7
|
+
smiles = "CCO" # ethanol
|
|
8
8
|
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
9
9
|
assert_not_nil(rw_mol)
|
|
10
10
|
assert_equal(3, rw_mol.get_num_atoms)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def test_mol_to_mol_block
|
|
14
|
-
smiles =
|
|
14
|
+
smiles = "CCO" # ethanol
|
|
15
15
|
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
16
16
|
mdl = rw_mol.mol_to_mol_block(true, -1, false)
|
|
17
17
|
assert_not_nil(mdl)
|
|
18
|
-
assert(mdl.include?(
|
|
18
|
+
assert(mdl.include?("V2000") || mdl.include?("V3000"))
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def test_mol_from_mol_block
|
|
22
|
-
smiles =
|
|
22
|
+
smiles = "c1ccccc1" # benzene
|
|
23
23
|
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
24
24
|
mdl = rw_mol.mol_to_mol_block(true, -1, false)
|
|
25
25
|
|
|
@@ -30,26 +30,41 @@ class RDKitTest < Test::Unit::TestCase
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def test_mol_to_smiles
|
|
33
|
-
smiles =
|
|
33
|
+
smiles = "CCO"
|
|
34
34
|
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
35
35
|
output_smiles = RDKitChem.mol_to_smiles(rw_mol)
|
|
36
36
|
assert_not_nil(output_smiles)
|
|
37
|
-
assert_equal(
|
|
37
|
+
assert_equal("CCO", output_smiles)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_sanitize_mol
|
|
41
|
+
smiles = "c1ccccc1" # benzene
|
|
42
|
+
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
43
|
+
|
|
44
|
+
# sanitize_mol returns an integer (0 for success usually, or bitmask of operations failed)
|
|
45
|
+
# It might return different things based on SWIG wrapping details observed in MolOps.i
|
|
46
|
+
# The SWIG wrapper returns the operation that failed (0 if all successful).
|
|
47
|
+
result = RDKitChem.sanitize_mol(rw_mol, RDKitChem::SANITIZE_ALL)
|
|
48
|
+
assert_equal(0, result, "sanitize_mol should return 0 (success)")
|
|
49
|
+
|
|
50
|
+
result = RDKitChem.sanitize_mol(rw_mol)
|
|
51
|
+
assert_equal(0, result, "sanitize_mol should return 0 (success)")
|
|
38
52
|
end
|
|
39
53
|
|
|
40
54
|
def test_cholesterol
|
|
41
55
|
# Cholesterol without chirality
|
|
42
|
-
smiles =
|
|
56
|
+
smiles = "CC(C)CCCC(C)C1CCC2C1(CCC3C2CC=C4C3(CCC(C4)O)C)C"
|
|
43
57
|
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
44
58
|
assert_not_nil(rw_mol)
|
|
45
|
-
assert_equal(28, rw_mol.get_num_atoms)
|
|
59
|
+
assert_equal(28, rw_mol.get_num_atoms) # C27H46O has 28 heavy atoms (27 C + 1 O)
|
|
46
60
|
end
|
|
47
61
|
|
|
48
62
|
def test_conformer_ownership
|
|
63
|
+
# FIXME: This test causes a segfault (exit code 139) likely due to GC/double-free issues.
|
|
49
64
|
# Test that conformer ownership is properly transferred to the molecule.
|
|
50
65
|
# This verifies the DISOWN directive works - without it, Ruby GC and C++
|
|
51
66
|
# destructor both try to free the Conformer, causing a double-free segfault.
|
|
52
|
-
smiles =
|
|
67
|
+
smiles = "CCO" # ethanol
|
|
53
68
|
rw_mol = RDKitChem::RWMol.mol_from_smiles(smiles)
|
|
54
69
|
|
|
55
70
|
# Create a conformer with 3D coordinates
|
|
@@ -59,7 +74,7 @@ class RDKitTest < Test::Unit::TestCase
|
|
|
59
74
|
conf.set_atom_pos(2, RDKitChem::Point3D.new(2.0, 1.0, 0.0))
|
|
60
75
|
|
|
61
76
|
# Add conformer to molecule (ownership transfers to C++)
|
|
62
|
-
conf_id = rw_mol.
|
|
77
|
+
conf_id = rw_mol.add_conf(conf, true)
|
|
63
78
|
assert(conf_id >= 0, "Conformer should be added successfully")
|
|
64
79
|
|
|
65
80
|
# Verify conformer was added
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rdkit_chem
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2025.09.3.
|
|
4
|
+
version: 2025.09.3.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- An Nguyen
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-01-22 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: rake
|
|
@@ -136,6 +137,7 @@ homepage: https://github.com/CamAnNguyen/rdkit-chem
|
|
|
136
137
|
licenses:
|
|
137
138
|
- BSD-3-Clause
|
|
138
139
|
metadata: {}
|
|
140
|
+
post_install_message:
|
|
139
141
|
rdoc_options: []
|
|
140
142
|
require_paths:
|
|
141
143
|
- lib
|
|
@@ -150,7 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
150
152
|
- !ruby/object:Gem::Version
|
|
151
153
|
version: '0'
|
|
152
154
|
requirements: []
|
|
153
|
-
rubygems_version:
|
|
155
|
+
rubygems_version: 3.5.22
|
|
156
|
+
signing_key:
|
|
154
157
|
specification_version: 4
|
|
155
158
|
summary: Ruby gem for RDKit
|
|
156
159
|
test_files:
|