What happens if I link two different libraries providing the same symbols in Visual Studio?

35 Views Asked by At

Background: I have Python 3.11 and development source installed on my Windows machine. The associated binaries are

  • python3.dll
  • python311.dll

The binary python3.dll implements a subset of python311.dll. The restricted python3.dll is intended to provide Python extension developers a stable API across Python versions. The Python documentation instructs developers to link against one or the other.

What happens in the Windows/MSVC ecosystem when I have my own binary which calls code from #include <Python.h> and link against both import libraries python3.lib and python311.lib? Specifically the linker commands include

link.exe
...
.../libs/python311.lib
.../libs/python3.lib

I have actually tried this and linking succeeded with no errors. I was surprised because I would have expected a duplicate symbol definition error. The resulting binary ran without any perceivable issues.

Is this okay to do in the Python case, and also in the general case? In the Python case, I happened to know that python3.dll implements the symbols through a forwarding export to python311.dll, by manually expecting the export table using the dependencies application. See screenshot, which is actually for python3.dll for Python 3.12, because I recently upgraded my Python. python3.dll

1

There are 1 best solutions below

0
Martin. On

I can't speak to the general behaviour, but I can share a specific issue I've seen when linking against both python3.lib and python310.lib. This will cause problems if the program relies on the user's Python installations and their PATH environment variable rather than an embedded Python installation, and if the user has multiple Python versions installed. For example, if the user's PATH has something like:

  • ...
  • C:\Python311
  • C:\Python310
  • ...

Then when launching the program, C:\Python310\python310.dll will be loaded as expected, but C:\Python311\python3.dll will be loaded instead of C:\Python310\python3.dll, since the former appeared first in the PATH. That python3.dll will then forward calls made to it to C:\Python311\python311.dll.

Following that, if Python is initialized through Py_InitializeFromConfig(), this will happen in python310.dll (since it is a part of the stable API). But calls to functions which are part of the stable API, and which expect the embedded Python to be initialized (such as PyImport_ImportModule()), will happen in python311.dll and will fail, potentially with an access violation. As I understand, this is because python310.dll and python311.dll each have an independent internal state, and that state has not been initialized in python311.dll.