Post

RDkit Windows版

RDkit Windows版

笔者C盘比较紧张,一直因为MSVC吓人的存储空间占用没舍得装,用wsl里的mingw交叉编译凑合。昨天终于狠下心清理了一顿,装上之后真香了。打算编译个RDkit Windows版给以后开发用。

编译

下载源码

1
git clone https://github.com/rdkit/rdkit.git

rdkit需要x64环境,如果MSVC默认进了x86的MSVC,会报一些乱七八糟的错。运行cl以检查:

1
2
3
4
5
6
7
(rdkit_cpp) D:\MSVC_work\RDkit\rdkit>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.51.36246 for x64
版权所有(C) Microsoft Corporation。保留所有权利。

cl: 命令行 error D8003 :缺少源文件名

(rdkit_cpp) D:\MSVC_work\RDkit\rdkit>

如果发现是x86的,可能需要手动切换

1
call "E:\MSVC\VC\Auxiliary\Build\vcvars64.bat"

配置:

1
2
3
4
5
6
7
8
9
10
cmake -S . -B build-static -G Ninja ^
  -DCMAKE_BUILD_TYPE=Release ^
  -DCMAKE_INSTALL_PREFIX=D:/MSVC_work/RDkit/rdkit/rdkit-static ^
  -DRDK_INSTALL_INTREE=OFF ^
  -DRDK_BUILD_PYTHON_WRAPPERS=OFF ^
  -DRDK_BUILD_CPP_TESTS=OFF ^
  -DBUILD_TESTING=OFF ^
  -DBUILD_SHARED_LIBS=OFF ^
  -DRDK_INSTALL_STATIC_LIBS=ON ^
  -DRDK_INSTALL_DLLS_MSVC=OFF

此处某些库本地没有的话会去GitHub下载,但是网络问题众所周知。如果下不下来,可以考虑conda装一个,然后加flag:

1
  -DCMAKE_PREFIX_PATH=%CONDA_PREFIX%\Library

成功配置CMake后,编译安装:

1
2
cmake --build build-static
cmake --install build-static

此处笔者遇到了ChemDraw字符相关的报错

1
2
3
4
5
External\ChemDraw\chemdraw\chemdraw\CDXObject.cpp
error C2065: “kUnicodeCodePointEmDash”: 未声明的标识符
error C2065: “kUnicodeCodePointBullet”: 未声明的标识符
error C2065: “kUnicodeCodePointEllipsis”: 未声明的标识符
error C2065: “kUnicodeCodePointAngstrom”: 未声明的标识符

找AI商量了一下,发现运行cmake之前,设置一个CXXFLAGS之后就可以正常配置:

1
set "CXXFLAGS=/utf-8"

构建完毕之后,为了偷懒,可以做个CMakePresets.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{
  "version": 6,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 25,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "msvc-ninja-static",
      "displayName": "MSVC Ninja Static RDKit",
      "description": "Configure RDKit static libraries with MSVC + Ninja.",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build-static",
      "installDir": "${sourceDir}/rdkit-static",

      "architecture": {
        "value": "x64",
        "strategy": "external"
      },

      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",

        "CMAKE_PREFIX_PATH": "D:/program/miniconda/envs/rdkit_cpp/Library",

        "RDK_INSTALL_INTREE": "OFF",
        "RDK_BUILD_PYTHON_WRAPPERS": "OFF",
        "RDK_BUILD_CPP_TESTS": "OFF",
        "BUILD_TESTING": "OFF",
        "BUILD_SHARED_LIBS": "OFF",
        "RDK_INSTALL_STATIC_LIBS": "ON",
        "RDK_INSTALL_DLLS_MSVC": "OFF",
        "RDK_BUILD_CHEMDRAW_SUPPORT": "ON"
      },

      "environment": {
        "CXXFLAGS": "/utf-8",
        "CL": null,
        "_CL_": null,
        "PATH": "D:/program/miniconda/envs/rdkit_cpp/Library/bin;D:/program/miniconda/envs/rdkit_cpp/Scripts;D:/program/miniconda/envs/rdkit_cpp;$penv{PATH}"
      },

      "vendor": {
        "microsoft.com/VisualStudioSettings/CMake/1.0": {
          "hostOS": [ "Windows" ]
        }
      }
    }
  ],

  "buildPresets": [
    {
      "name": "build-rdkit-static",
      "displayName": "Build RDKit Static",
      "configurePreset": "msvc-ninja-static"
    },
    {
      "name": "install-rdkit-static",
      "displayName": "Install RDKit Static",
      "configurePreset": "msvc-ninja-static",
      "targets": [ "install" ]
    }
  ],

  "workflowPresets": [
    {
      "name": "build-and-install-rdkit-static",
      "displayName": "Build and Install RDKit Static",
      "description": "Configure, build, and install RDKit static libraries.",
      "steps": [
        {
          "type": "configure",
          "name": "msvc-ninja-static"
        },
        {
          "type": "build",
          "name": "build-rdkit-static"
        },
        {
          "type": "build",
          "name": "install-rdkit-static"
        }
      ]
    }
  ]
}

玩具测试

笔者很早就想用RDkit的功能做个smiles转3D,之前有python脚本,打包之后600多M吓哭了,现在有MSVC,就可以极大地削减体积了。脚本太长,读者若有兴趣可自行下载。在CMakeLists中,需要把刚才安装的RDkit库添加到CMAKE_PREFIX_PATH使得新项目能找到RDkit库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
cmake_minimum_required(VERSION 3.21)

project(confsearch LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(RDKIT_STATIC_ROOT
    "D:/MSVC_work/RDkit/rdkit/rdkit-static"
    CACHE PATH "Path to self-built static RDKit install prefix"
)

set(CONDA_ROOT
    "D:/program/miniconda/envs/rdkit_cpp"
    CACHE PATH "Conda environment used for RDKit dependencies"
)

list(PREPEND CMAKE_PREFIX_PATH
    "${RDKIT_STATIC_ROOT}"
    "${CONDA_ROOT}/Library"
)

find_package(RDKit CONFIG REQUIRED)

add_executable(confsearch main.cpp)

if(MSVC)
    target_compile_options(confsearch PRIVATE /utf-8)
endif()

target_link_libraries(confsearch PRIVATE
    RDKit::SmilesParse
    RDKit::DistGeomHelpers
    RDKit::ForceFieldHelpers
    RDKit::ForceField
    RDKit::DistGeometry
    RDKit::EigenSolvers
    RDKit::Optimizer
    RDKit::MolAlign
    RDKit::SubstructMatch
    RDKit::GraphMol
    RDKit::RDGeometryLib
    RDKit::DataStructs
    RDKit::RDGeneral
)

install(TARGETS confsearch RUNTIME DESTINATION .)

# Optional: collect non-RDKit runtime DLLs, e.g. boost/zlib from conda.
# This should no longer copy RDKit DLLs if the static RDKit package is used.
install(CODE [[
  set(EXE "$<TARGET_FILE:confsearch>")
  set(DEST "${CMAKE_INSTALL_PREFIX}")
  set(CONDA_BIN "D:/program/miniconda/envs/rdkit_cpp/Library/bin")

  file(GET_RUNTIME_DEPENDENCIES
    EXECUTABLES "${EXE}"
    DIRECTORIES "${CONDA_BIN}"
    PRE_EXCLUDE_REGEXES
      "api-ms-.*"
      "ext-ms-.*"
    POST_EXCLUDE_REGEXES
      ".*[Ww]indows[/\\].*"
      ".*[Ss]ystem32[/\\].*"
      ".*RDKit.*\\.dll"
    RESOLVED_DEPENDENCIES_VAR deps
    UNRESOLVED_DEPENDENCIES_VAR missing
  )

  foreach(dll IN LISTS deps)
    file(INSTALL DESTINATION "${DEST}" TYPE FILE FILES "${dll}")
  endforeach()

  if(missing)
    message(WARNING "Unresolved runtime dependencies: ${missing}")
  endif()
]])
This post is licensed under CC BY 4.0 by the author.
Total hits!