Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
501 views
in Technique[技术] by (71.8m points)

python - "unresolved external symbol"-error when linking a Cython extension against a C library on Windows

I am learning Cython and tried to run a simple example found here: making C library callable.

I used VS 2019 to create mylib.lib and setup.py to build the Cython-extension (for details and code see below), however the linker fails with error:

error LNK2001: unresolved external symbol hello

Yet when I ran nm mylib.lib that I found in other post I can see that the symbol _hello is present:

D:Codesgit_foldersmy_repositoryCython_testlib>nm mylib.lib
...
Debug/examples.obj:
...
00000000 T _hello
...

What is going wrong?


Code:

pyexamples.pyx

cdef extern from "examples.h":
    void hello(const char *name)

def py_hello(name: bytes) -> None:
    hello(name)

setup.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

examples_extension = Extension(
    name="pyexamples",
    sources=["pyexamples.pyx"],
    libraries=["mylib"],
    library_dirs=["lib"],
    include_dirs=["lib"]
)
setup(
    name="pyexamples",
    ext_modules=cythonize([examples_extension])
)

examples.c

#include <stdio.h>
#include "examples.h"

void hello(const char *name) {
    printf("hello %s
", name);
}

examples.h

#ifndef EXAMPLES_H
#define EXAMPLES_H

void hello(const char *name);

#endif

However if I run this command, python setup.py build_ext --inplace

I got this error.

running build_ext
building 'pyexamples' extension
C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.27.29110inHostX86x64cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -Ilib -IC:Usersswsyoanaconda3include -IC:Usersswsyoanaconda3include "-IC:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.27.29110ATLMFCinclude" "-IC:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.27.29110include" "-IC:Program Files (x86)Windows Kits10include10.0.18362.0ucrt" "-IC:Program Files (x86)Windows Kits10include10.0.18362.0shared" "-IC:Program Files (x86)Windows Kits10include10.0.18362.0um" "-IC:Program Files (x86)Windows Kits10include10.0.18362.0winrt" "-IC:Program Files (x86)Windows Kits10include10.0.18362.0cppwinrt" /Tcpyexamples.c /Fobuildemp.win-amd64-3.7Releasepyexamples.obj
pyexamples.c
C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.27.29110inHostX86x64link.exe /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:lib /LIBPATH:C:Usersswsyoanaconda3libs /LIBPATH:C:Usersswsyoanaconda3PCbuildamd64 "/LIBPATH:C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.27.29110ATLMFClibx64" "/LIBPATH:C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.27.29110libx64" "/LIBPATH:C:Program Files (x86)Windows Kits10lib10.0.18362.0ucrtx64" "/LIBPATH:C:Program Files (x86)Windows Kits10lib10.0.18362.0umx64" mylib.lib /EXPORT:PyInit_pyexamples buildemp.win-amd64-3.7Releasepyexamples.obj /OUT:D:git_foldersmy_repositoryCython_testpyexamples.cp37-win_amd64.pyd /IMPLIB:buildemp.win-amd64-3.7Releasepyexamples.cp37-win_amd64.lib
   Creating library buildemp.win-amd64-3.7Releasepyexamples.cp37-win_amd64.lib and object buildemp.win-amd64-3.7Releasepyexamples.cp37-win_amd64.exp
pyexamples.obj : error LNK2001: unresolved external symbol hello
D:git_foldersmy_repositoryCython_testpyexamples.cp37-win_amd64.pyd : fatal error LNK1120: 1 unresolved externals
error: command 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\bin\HostX86\x64\link.exe' failed with exit status 1120

More details:

Based on comments below, I ran dumpbin mylib.lib command to see if hello function is in the libraries. Is this right way to do it ? I don't see the name hello in this summary though.

D:Codesgit_foldersmy_repositoryCython_testlib>dumpbin mylib.lib
Microsoft (R) COFF/PE Dumper Version 14.27.29111.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file mylib.lib

File Type: LIBRARY

  Summary

          E8 .chks64
         C94 .debug$S
          C8 .debug$T
         10A .drectve
           5 .msvcjmc
           A .rdata
           8 .rtc$IMZ
           8 .rtc$TMZ
         1B4 .text$mn

I also ran nm mylib.lib that I found in other post. You can see the _hello at the end of the summary.

D:Codesgit_foldersmy_repositoryCython_testlib>nm mylib.lib

Debugmylib.obj:
00000000 N .chks64
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$T
00000000 i .drectve
00000000 d .msvcjmc
00000000 r .rtc$IMZ
00000000 r .rtc$TMZ
00000000 t .text$mn
00000000 t .text$mn
         U @__CheckForDebuggerJustMyCode@4
010471b7 a @comp.id
80000391 a @feat.00
00000000 d __87B4E6C0_mylib@c
00000000 T __JustMyCode_Default
         U __RTC_CheckEsp
         U __RTC_InitBase
00000000 r __RTC_InitBase.rtc$IMZ
         U __RTC_Shutdown
00000000 r __RTC_Shutdown.rtc$TMZ
00000000 T _fnmylib

Debug/examples.obj:
00000000 N .chks64
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$S
00000000 N .debug$T
00000000 i .drectve
00000000 d .msvcjmc
00000000 r .rdata
00000000 r .rtc$IMZ
00000000 r .rtc$TMZ
00000000 t .text$mn
00000000 t .text$mn
00000000 t .text$mn
00000000 t .text$mn
00000000 t .text$mn
00000000 R ??_C@_09DEHHIH@hello?5?$CFs?6@
00000008 C ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9
         U @__CheckForDebuggerJustMyCode@4
010471b7 a @comp.id
80000391 a @feat.00
00000000 T ___local_stdio_printf_options
00000001 d __101834BA_corecrt_wstdio@h
00000003 d __2F33A99E_examples@c
00000002 d __AD6A91B7_stdio@h
00000000 d __F66CEB67_corecrt_stdio_config@h
         U __imp____acrt_iob_func
         U __imp____stdio_common_vfprintf
00000000 T __JustMyCode_Default
         U __RTC_CheckEsp
         U __RTC_InitBase
00000000 r __RTC_InitBase.rtc$IMZ
         U __RTC_Shutdown
00000000 r __RTC_Shutdown.rtc$TMZ
00000000 T __vfprintf_l
00000000 T _hello
00000000 T _printf

After I rebuild the project for x64 system( I had to change "Active solution platform" to x64 in the Build > Configuration Manager), here is result of dumpbin /symbols mylib.lib. I can see the hello function in the summary.

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Rebuild the (static) library for x64.

The symbol in your library is called _hello and not hello as one would expect for a x64-build (your extension is built for 64bit as can be seen in the logs).

On x64, MSVC doesn't mangle names when compiling as C-code so the resulting symbol is simple - hello, but it does mangle C-names on x86 (here documentation, here an example on godbolt.org):

  • __cdecl-calling convention (default for x86 if no special compile-flags are used) adds prefix _ to the name which would lead to the symbol being called _hello.
  • __stdcall-calling convention (if compiled with /Gz or the calling convention is explicitly specified, i.e. void __stdcall hello(char *)) adds prefix _ to the name and suffix @ with the number of bytes in the parameter list, i.e. it would lead to _hello@4.

Thus, it becomes clear, that your library is built in 32bit and thus cannot be linked to a 64bit-dll.


Were the library a dll, the symbol's names would be slightly different. Calling

__declspec( dllimport ) void hello(char* a);

would lead to (see live on godbolt.org):

  • __imp__hello (two underscores between imp and hello) for x86/32bit, i.e. prefix __imp_ due to declspec(dllimport) and prefix _ due to name mangling of __cdecl on x86.
  • __imp_hello (one underscores between imp and hello) for x64/64bit, i.e. only prefix __imp_ due to declspec(dllimport).

There is also a more direct way to see, that the library is 32bit, by running:

dumpbin /header mylibrary.lib

which would produce machine (x86) for 32bit build:

...
File Type: LIBRARY

FILE HEADER VALUES
             14C machine (x86)
...

but machine (x64) for 64bit build:

...
File Type: LIBRARY

FILE HEADER VALUES
            8664 machine (x64)

Furthermore, the MSVC-linker used to produce a warning when there is a machine-mismatch:

mylibrary.lib : warning LNK4272: library machine type 'X86' conflicts with target machine type 'x64'

Not sure why it wasn't present in your logs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...