pypa / pypa/setuptools

c++-python-cmake-binding-stdin-line-1-importerror-dynamic-module-does-not-def

Open
#2,079 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.9k
Forks
1.4k
Avg merge
1d 1h
Merged PRs (30d)
1

Description

I am trying to install a module with python and create an extension of a cop files detectc.cpp But after I do

python3 setup.py install

install success. then.

python 
import detect

I get error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dynamic module does not define module export function (PyInit_detectc)

Files to reproduce:

setup.py

from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext
import os
import platform
import subprocess
import sys
from pprint import pprint

c_module_name = "detectc"

cmake_cmd_args = []
for f in sys.argv:
    if f.startswith('-D'):
        cmake_cmd_args.append(f)

for f in cmake_cmd_args:
    sys.argv.remove(f)

class CMakeBuild(build_ext):
    def build_extensions(self):
        try:
            out = subprocess.check_output(['cmake', '--version'])
        except OSError:
            raise RuntimeError('Cannot find CMake executable')

        for e in self.extensions:
            extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(e.name)))
            cfg = 'Release'
            cmake_args = [
                    '-DPYTHON_EXECUTABLE=/home/ubuntu/anaconda3/envs/dutchman/bin/python',
                    '-DCMAKE_BUILD_TYPE=%s' % cfg,
                    '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir),
                    '-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), self.build_temp),
#                     '-DPYTHON_EXECUTABLE={}'.format(sys.executable)
                ]
            build_ext.build_extensions(self)

            cmake_args += cmake_cmd_args
            print(cmake_args)
            print(e.cmake_lists_dir)
            if not os.path.exists(self.build_temp):
                os.makedirs(self.build_temp)
            subprocess.check_call(['cmake', e.cmake_lists_dir] + cmake_args,
                                  cwd=self.build_temp)

            subprocess.check_call(['cmake', '--build', '.', '--config', cfg],
                                  cwd=self.build_temp)



class CMakeExtension(Extension):
    def __init__(self, name, cmake_lists_dir='.', **kwa):
        Extension.__init__(self, name, sources=[], **kwa)
        self.cmake_lists_dir = os.path.abspath(cmake_lists_dir)
        print(self.cmake_lists_dir)


setup(name='detectc',
      version='1.1.0',
      description='Generate displacement fields with known volume changes',
      author='Martino Pilia',
      author_email='martino.pilia@gmail.com',
      install_requires=['numpy>=1.15.1'],
      ext_modules=[CMakeExtension(c_module_name)],
      cmdclass={'build_ext': CMakeBuild},
      )

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(detectc_)

find_package(PythonInterp 3.5 REQUIRED)

# This comes to hand if we also need to use the NumPy C API
exec_program(${PYTHON_EXECUTABLE}
             ARGS "-c \"import numpy; print(numpy.get_include())\""
             OUTPUT_VARIABLE NUMPY_INCLUDE_DIR
             RETURN_VALUE NUMPY_NOT_FOUND
            )

set(SRCS "detectc.cpp")
#add_library(detectc_ SHARED ${SRCS})
add_library(detectc_ ${SRCS})

set_target_properties(
    detectc_
    PROPERTIES
        PREFIX ""
        OUTPUT_NAME "detectc"
        LINKER_LANGUAGE CXX
    )

# Find NumPy headers
exec_program(${PYTHON_EXECUTABLE}
    ARGS "-c \"import numpy; print(numpy.get_include())\""
    OUTPUT_VARIABLE NUMPY_INCLUDE_DIR
    RETURN_VALUE NUMPY_NOT_FOUND
    )
if(NUMPY_NOT_FOUND)
    message(FATAL_ERROR "NumPy headers not found")
endif()

# Find Python headers
exec_program(${PYTHON_EXECUTABLE}
    ARGS "-c \"import sysconfig; print(sysconfig.get_paths()['include'])\""
    OUTPUT_VARIABLE PYTHON_INCLUDE_DIRS
    RETURN_VALUE PYTHON_INCLUDE_DIRS_NOT_FOUND
    )
if(PYTHON_INCLUDE_DIRS_NOT_FOUND)
    message(FATAL_ERROR "Python headers not found")
endif()


target_include_directories(detectc_ PUBLIC
    ${PYTHON_INCLUDE_DIRS}
    ${NUMPY_INCLUDE_DIR}
    )

detectc.cpp

#include <python3.5/Python.h>

static PyObject* division(PyObject *self, PyObject *args);

// Exported methods are collected in a table
PyMethodDef method_table[] = {
    {"division", division, METH_VARARGS, "Method docstring"},
    {NULL, NULL, 0, NULL} // Sentinel value ending the table
};


// A struct contains the definition of a module
PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "detectc", // Module name
    "This is the module docstring",
    -1,   // Optional size of the module state memory
    method_table,
    NULL, // Optional slot definitions
    NULL, // Optional traversal function
    NULL, // Optional clear function
    NULL  // Optional module deallocation function
};


// The module init function
// PyMODINIT_FUNC PyInit__detectc(void) {
//     return PyModule_Create(&moduledef);
// }

PyMODINIT_FUNC PyInit_detectc() {
    return PyModule_Create(&moduledef);
}

// This is the definition of a method
static PyObject* division(PyObject *self, PyObject *args) {
    long dividend, divisor;
    if (!PyArg_ParseTuple(args, "ll", &dividend, &divisor)) {
        return NULL;
    }
    if (0 == divisor) {
        PyErr_Format(PyExc_ZeroDivisionError, "Dividing %d by zero!", dividend);
        return NULL;
    }
    return PyLong_FromLong(dividend / divisor);
}

File structure

(---) ubuntu@---:~/robo/ext_test/Detect$ ls
CMakeLists.txt  detectc.cpp  __init __.py  setup.py

I have been stuck on this for 4 days now. There is no way out. Please help!!! Any hints highly appreciated.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with setup.py, CMakeLists.txt, and detectc.cpp, then reproduce the failure using the listed python3 setup.py install and import commands. Compare the extension name, generated artifact, and Python initialization entry point; done means the sample module installs and imports without the reported ImportError.

Written by the indexing model from the issue text.

Assessment

Tech stack
cmake, cpp, python
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.