Skip to content

[BUG]: staticly import Python modules in C++ global scope #4263

@XuehaiPan

Description

@XuehaiPan

Required prerequisites

Problem description

Failed to load a .pyd library if it contains global imports with Python 3.8-3.10 (Python 3.6-3.7 works fine). See https://github.com/metaopt/optree/actions/runs/3288272968/jobs/5418431116 for more details.

  + python -c "import optree"
  Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "C:\Users\runneradmin\AppData\Local\Temp\cibw-run-in9p445l\cp38-win_amd64\venv-test\lib\site-packages\optree\__init__.py", line 17, in <module>
      from optree.ops import (
    File "C:\Users\runneradmin\AppData\Local\Temp\cibw-run-in9p445l\cp38-win_amd64\venv-test\lib\site-packages\optree\ops.py", line 24, in <module>
      import optree._C as _C
  ImportError: DLL load failed while importing _C: A dynamic link library (DLL) initialization routine failed.

Related code:

https://github.com/metaopt/optree/blob/fa1bb70f2e92f5a3c110c00fc1790dd20d36b72d/include/utils.h#L51-L56

For Python 3.8-3.10, the import fails if there are C++ global-level imports:

namespace py = pybind11;

const py::module_ collections_module = py::module_::import("collections");

void foo(py::handle) {
    const py::object OrderedDict = collections_module.attr("OrderedDict");
}

Everything works fine if I change this into a function static variable:

namespace py = pybind11;

void foo(py::handle) {
    static const py::module_ collections_module = py::module_::import("collections");
    const py::object OrderedDict = collections_module.attr("OrderedDict");
}

Reproducible example code

Directory structure:

.
├── CMakeLists.txt
├── test.cpp
└── third-party
    └── pybind11
        ├── include
        ...

Source files:

// test.cpp

#include <pybind11/pybind11.h>

namespace test {

namespace py = pybind11;

const py::module_ collections_module = py::module_::import("collections");

void BuildModule(py::module& mod) {}

}  // namespace test

PYBIND11_MODULE(_C, mod) { test::BuildModule(mod); }
# CMakeLists.txt

cmake_minimum_required(VERSION 3.4)
project(test LANGUAGES CXX)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

set(CMAKE_CXX_STANDARD 14)

find_package(Threads REQUIRED)           # -pthread
find_package(OpenMP REQUIRED)            # -Xpreprocessor -fopenmp
set(CMAKE_POSITION_INDEPENDENT_CODE ON)  # -fPIC
set(CMAKE_CXX_VISIBILITY_PRESET hidden)  # -fvisibility=hidden

if(MSVC)
    string(APPEND CMAKE_CXX_FLAGS " /Wall")
    string(APPEND CMAKE_CXX_FLAGS_DEBUG " /Zi")
    string(APPEND CMAKE_CXX_FLAGS_RELEASE " /O2 /Ob2")
else()
    string(APPEND CMAKE_CXX_FLAGS " -Wall")
    string(APPEND CMAKE_CXX_FLAGS_DEBUG " -g -Og")
    string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O3")
endif()

if(NOT DEFINED PYTHON_EXECUTABLE)
    if(WIN32)
        set(PYTHON_EXECUTABLE "python.exe")
    else()
        set(PYTHON_EXECUTABLE "python")
    endif()
endif()

add_subdirectory(third_party/pybind11)
include_directories(third_party/pybind11/include)

include_directories("${CMAKE_SOURCE_DIR}")
set(csrc test.cpp)

pybind11_add_module(_C THIN_LTO "${csrc}")

target_link_libraries(_C PUBLIC)

Command-line and results:

Python 3.7:

$ conda create -n py37 python=3.7 -y
$ conda activate py37
$ mkdir build-py37
$ cd build-py37

$ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
-- Building for: Visual Studio 17 2022
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The CXX compiler identification is MSVC 19.33.31629.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.33.31629/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - not found
-- Found Threads: TRUE  
-- Found OpenMP_CXX: -openmp (found version "2.0") 
-- Found OpenMP: TRUE (found version "2.0")  
-- pybind11 v2.11.0 dev1
-- Found PythonInterp: python.exe (found suitable version "3.7.13", minimum required is "3.6") 
-- Found PythonLibs: C:/Users/PanXuehai/Miniconda3/envs/py37/libs/python37.lib
-- Performing Test HAS_MSVC_GL_LTCG
-- Performing Test HAS_MSVC_GL_LTCG - Success
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/PanXuehai/Projects/test/build-py37

$ cmake --build .
exit with code 0

$ cd Debug
$ ls

   Directory: C:\Users\PanXuehai\Projects\test\build-py37\Debug

_C.cp37-win_amd64.pyd  _C.exp                 _C.lib                 _C.pdb

$ python -c 'import collections; import _C'
exit with code 0

Python 3.10:

$ conda create -n py310 python=3.10 -y
$ conda activate py310
$ mkdir build-py310
$ cd build-py310

$ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
-- Building for: Visual Studio 17 2022
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The CXX compiler identification is MSVC 19.33.31629.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.33.31629/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - not found
-- Found Threads: TRUE  
-- Found OpenMP_CXX: -openmp (found version "2.0") 
-- Found OpenMP: TRUE (found version "2.0")  
-- pybind11 v2.11.0 dev1
-- Found PythonInterp: python.exe (found suitable version "3.10.6", minimum required is "3.6") 
-- Found PythonLibs: C:/Users/PanXuehai/Miniconda3/envs/py38/libs/python310.lib
-- Performing Test HAS_MSVC_GL_LTCG
-- Performing Test HAS_MSVC_GL_LTCG - Success
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/PanXuehai/Projects/test/build-py310

$ cmake --build .
exit with code 0

$ cd Debug
$ ls

   Directory: C:\Users\PanXuehai\Projects\test\build-py310\Debug

_C.cp310-win_amd64.pyd  _C.exp                 _C.lib                 _C.pdb

$ python -c 'import collections; import _C'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: DLL load failed while importing _C: A dynamic link library (DLL) initialization routine failed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageNew bug, unverified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions