OpenShot / libopenshot

OpenShot Video Library (libopenshot) is a free, open-source project dedicated to delivering high quality video editing, animation, and playback solutions to the world. API currently supports C++, Python, and Ruby.
http://www.openshot.org
GNU Lesser General Public License v3.0
1.24k stars 267 forks source link

[Beginner] Builds fine on Windows but fails to load #359

Closed mkarg closed 4 years ago

mkarg commented 4 years ago

I'd like to become a OpenShot contributor, so I followed these excellent instructions: https://github.com/OpenShot/libopenshot/wiki/Windows-Build-Instructions with the latest code from develop branch.

libopenshot-audio.dll and libopenshot.dll both build fine (no errors reported), so I copy them into my original OpenShot 2.4.4 installation directory (overwriting the orignals) and try to start launch.exe. Unfotunately at that point I get an immediate message that the needed DLL could not be found: ImportError: DLL load failed: The module could not get found.. Unfortunately it does not tell me which one. If I use the original DLLs, then it works.

I'm stuck here as I have no clue how to get more details on the cause of the problem. I even don't know if there is a log file I could check.

It would be really kind if someone could help me get this running. :-)

mkarg commented 4 years ago

Apparently this seems to be a bug of the build script: It configures make install to put openshot.py into folder C:/msys64/usr/lib/python3.8/site-packages...

-- Found PythonLibs: C:/msys64/mingw64/lib/libpython3.8.dll.a (found suitable version "3.8.0", minimum required is "3")
-- Found PythonInterp: C:/msys64/mingw64/bin/python3.exe (found suitable version "3.8", minimum required is "3")
PYTHON_MODULE_PATH: C:/msys64/usr/lib/python3.8/site-packages
-- Installing: C:/msys64/usr/lib/python3.8/site-packages/_openshot.pyd
-- Installing: C:/msys64/usr/lib/python3.8/site-packages/openshot.py
-- Installing: C:/msys64/usr/lib/libopenshot.dll.a
-- Installing: C:/msys64/usr/lib/libopenshot.dll

...but python3 searches it in a different folder...

>>> for path in sys.path:
...     print(path)
...
C:/msys64/mingw64/lib/python38.zip
C:/msys64/mingw64/lib/python3.8
C:/msys64/mingw64/lib/python3.8/lib-dynload
C:/msys64/mingw64/lib/python3.8/site-packages

The question is, why CMake decides that the libraries shall be put into C:/msys64/mingw as apparently Python is not configured to search that path?

I am neither a Python nor CMake professional, so it would be nice if someone could point me to the place where CMake decides about PYTHON_MODULE_PATH.

mkarg commented 4 years ago

@ferdnyc Can you please guide me with this issue? I developed two effect changes which work really fine on Ubuntu, but before I send the PR I really want to test them on Windows... :-)

ferdnyc commented 4 years ago

@mkarg

Yeah, apologies, I saw this the other day and had intended to respond to it, but I was on my phone, and... well, here we are.

The process by which the Python bindings are installed is... well, it's a mess, really, and definitely only possibly-useful on Linux. That's the only place we've tested it, because it's the only place we use it. On MacOS and Windows, OpenShot is distributed as a self-contained application, so the placement of the libraries is handled by the installer — CMake doesn't know how to install the Python components on Windows, since they need to be installed inside the OpenShot installation directory.

When our own build hosts compile libopenshot-audio and libopenshot, they run with -DCMAKE_INSTALL_PREFIX=install-x64 on the cmake command line, which causes make install to place the install tree in a subdirectory of the build dir. Then, the contents of install-x64 are passed along the compilation chain, so that libopenshot adds its own installed files to libopenshot-audio's, and then they're all available to openshot-qt when it's assembling the components of the frozen application directory and packaging it all into the OS-native installer (or AppImage, on Linux) distributable.

You can look at the .gitlab-ci.yml and .travis-ci.yml files at the root of each repo, to see how the various steps are performed on each OS. (But for Windows specifically, only .gitlab-ci.yml will contain anything of interest because Travis' Windows support is still too pathetic and broeken for us to use. I keep meaning to set up AppVeyor CI for Windows builds, but haven't gotten around to it yet.)

Running development builds

Long story short, make install currently has no ability to update the installed libopenshot or libopenshot-audio, on Windows. Heck, even developing on Linux I avoid using it — since installing a new library build every time I want to test it is a bit of an imposition (and could potentially break my working install), I run test code directly from the build dir:

$ cd /path/to/checked/out/openshot-qt/src
$ PYTHONPATH=/path/to/checked/out/libopenshot/build/src/bindings/python python3 ./launch.py

However, since you're working on Windows, my recommendation would be to build libopenshot and/or libopenshot-audio with -DCMAKE_INSTALL_PREFIX=install-x64, do the make install into that path after building, and then copy the relevant files from ${CMAKE_BINARY_DIR}/install-x64/... over the existing ones (or alongside, for new files) inside (presumably) C:\Program Files\OpenShot Video Editor\...

(There would be very few, "the relevant files" are, for the most part:

...Not 100% sure about the naming on the last file, it's _openshot.so when built under Linux and I'm pretty sure _openshot.dylib under MacOS, but the Windows naming might differ. But it's really just, like, 4 files, all the rest are supplied either by openshot-qt or by library dependencies.

ferdnyc commented 4 years ago

However, since you're working on Windows, my recommendation would be to build libopenshot and/or libopenshot-audio with -DCMAKE_INSTALL_PREFIX=install-x64, do the make install into that path after building, and then copy the relevant files from ${CMAKE_BINARY_DIR}/install-x64/... over the existing ones (or alongside, for new files) inside (presumably) C:\Program Files\OpenShot Video Editor\...

BTW, all of this is not, by any means, to say that CMake couldn't be extended with the ability to do that automatically (or at least more intelligently). Or that we'd be against extending it that way. To be honest, until now nobody's really expressed any interest, at least on Windows. Even getting libopenshot to successfully build on Windows is no small achievement, and anyone who's succeeded is generally too overwhelmed to fuss over things like installation. :wink:

But there's definitely room, I'd think, for a CMake configuration that, in concert with both -DCMAKE_INSTALL_PREFIX=C:\Program Files\OpenShot Video Editor\, and an enable option like -DWINDOWS_DEVEL_INSTALL=1 or similar, made the correct decisions to update the previously installer-created library files in an existing Windows install of OpenShot.

But it's really just, like, 4 files, all the rest are supplied either by openshot-qt or by library dependencies.

Actually, come to think of it: The first time you were to do this, you'll probably also have to update a lot of the dependency libraries, to the versions you compiled against.

OpenShot ships (somewhat by deliberate intent) packages that contain library versions that are far from the latest-and-greatest. They're installed on the build servers, and rarely updated unless they absolutely have to be. (And sometimes not even then.)

Those older versions are rarely still available in package collections, so even if you wanted to build against the same versions, you wouldn't be able to find them in pre-built binary form anywhere, and even finding source packages would probably be a fairly huge undertaking. So, the versions you'd be compiling against are almost certainly far newer than the ones that were included when you installed OpenShot from an installer package.

Which means that, the first time you were to do this, it would be a good idea to also go through and update the C:\Program Files\OpenShot Video Editor\... local copies of things like the FFmpeg (libav*.dll), ImageMagick (if built), Qt, PyQt5, and (possibly) Python files that were installed with OpenShot, so that you're running with the same versions you compiled against.

(Updating Python would be particularly treacherous, though, so I'd recommend not attempting that if it's at all possible to avoid it. PyQt5 is probably second-most likely to be extremely fragile, when attempting to update. FFmpeg is by far the most critical to keep in sync with the version used to build libopenshot, since their API is such a rapidly-moving target.)

ferdnyc commented 4 years ago

Which means that, the first time you were to do this, it would be a good idea to also go through and update the C:\Program Files\OpenShot Video Editor\... local copies of things like the FFmpeg (libav*.dll), ImageMagick (if built), Qt, PyQt5, and (possibly) Python files that were installed with OpenShot, so that you're running with the same versions you compiled against.

(CMake running on Windows actually does have some facility for automatically including dependencies in a project's install. I know Blender uses it, but so far that's all I know. I've been meaning to look at that some more, to figure out whether it's anything we could use.)

mkarg commented 4 years ago

@ferdnyc Thanks a lot for your great help! I will definitively try to make it work, and if I succeed, I will share whatever I could. :-)

ferdnyc commented 4 years ago

Oh, I wanted to mention this, also, in case you haven't picked it up already from some of the other past issues from other users working on libopenshot builds of their own:

The best way to test the whole stack's functional status and readiness to support OpenShot (if, indeed, the goal is to run OpenShot against the compiled library) is to load the Python module and test whether it responds to API requests (which would trigger loading libopenshot itself, in turn).

On Linux and MacOS, when it compiles the build tree CMake automatically sets the RPATH of the targets it builds so that they're able to load any linked libraries without having to be installed, which is why I can set PYTHONPATH to the Python build output directory and everything will work the way it should.

But AIUI Windows doesn't have a concept like RPATH, so it expects necessary DLLs to either be installed in well-known system locations, or to be present in the same directory as whatever's loading them. libopenshot builds targets in different directories, which is fairly typical. (It even installs them in different directories, which is probably wrong for Windows TBH.) I assume that would cause problems when it comes to testing.

What I'd do is, after building everything, copy the libopenshot and libopenshot-audio DLLs into the same dir as the Python bindings. Whether that's under your build dir in the src\bindings\python subir (where they're built), or whether you copy them out of there as well, get a directory that contains all four of the files I mentioned in the same place. Then, you should be able to test the Python interface the same way we would under Linux:

cd c:\path\to\cloned\libopenshot\build\src\bindings\python
set "PYTHONPATH=c:\path\to\cloned\libopenshot\build\src\bindings\python"
python3

Then, in Python, ideally:

>>> import sys
>>> import openshot
>>> print(sys.modules['openshot'])
<module 'openshot' from 'C:/.../libopenshot/build/src/bindings/python/openshot.py'>
>>> print(sys.modules['_openshot'])
<module '_openshot' from 'C:/.../libopenshot/build/src/bindings/python/_openshot.pyd'>
>>> print(openshot.Version)
0.2.3-dev1
>>> str(openshot.GetVersion())
'0.2.3-dev1'
>>> help(openshot.Timeline.__init__)
Help on function __init__ in module openshot:

__init__(self, width, height, fps, sample_rate, channels, channel_layout)
    __init__(openshot::Timeline self, int width, int height, Fraction fps, int sample_rate,
             int channels, openshot::ChannelLayout channel_layout) -> Timeline
>>> # We really need to add an openshot.LAYOUT_NONE to the layout enum; an oversight)
... t = openshot.Timeline(1280, 720, openshot.Fraction(30000,1001), 48000, 0,
... openshot.LAYOUT_MONO)
>>> c = openshot.Clip('/usr/share/pixmaps/fedora-logo.png')
>>> print(c.Reader().info.width, "×", c.Reader().info.height)
521 × 164

..And so on. If all that works as expected, your libopenshot build's in good shape.

mkarg commented 4 years ago

@ferdnyc Thank you so much for your kind help. Unfortunately it still does not not work, and I cannot understand why. See what happens:

Markus@Zauselmaus MSYS /c/Users/Markus/git/libopenshot/build/src/bindings/python
$ python3
Python 3.7.4 (default, Jul 11 2019, 09:35:14)
[GCC 9.1.0] on msys
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import openshot
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/c/Users/Markus/git/libopenshot/build/src/bindings/python/openshot.py", line 15, in <module>
    import _openshot
ModuleNotFoundError: No module named '_openshot'
>>>

Markus@Zauselmaus MSYS /c/Users/Markus/git/libopenshot/build/src/bindings/python
$ ls $PYTHONPATH
__pycache__  _openshot.pyd  cmake_install.cmake  CMakeFiles  libopenshot.dll  libopenshot-audio.dll  Makefile  openshot.py  pyopenshot_autogen

Apparently the missing module _openshot.pyd has to be found at some magic place (not just parallel to openshot.py and not just at CWD, as it is exactly there). But where...?! :face_with_head_bandage:

ferdnyc commented 4 years ago

@ferdnyc Thank you so much for your kind help. Unfortunately it still does not not work, and I cannot understand why. See what happens:

Ohh-kay, a few things I've discovered:

  1. The MSYS python3 doesn't seem to support .pyd files. It would never acknowledge any .pyd file I had anywhere as being even potentially loadable.
  2. The MinGW64 / MinGW32 python3, those do appear to recognize .pyd files. So, if you're running in an MSYS shell (with the standard MSYS2 graphical-installer setup), maybe try switching to the MinGW64 shell instead.
  3. It looks like PYTHONPATH set in the shell environment isn't sufficient, it also needs to be exported to get picked up by Python. That's probably something to do with the way the execution environment is handed off when launching .EXE files. You can check whether Python is picking up the $PYTHONPATH from the Python interpreter:
    >>> import sys
    >>> print(sys.path)
    ['', 'C:/msys64/mingw64/lib/python38.zip', 'C:/msys64/mingw64/lib/python3.8', 
    'C:/msys64/mingw64/lib/python3.8/lib-dynload', 'C:/msys64/mingw64/lib/python3.8/site-packages']
    Markus@Zauselmaus MSYS /c/Users/Markus/git/libopenshot/build/src/bindings/python
    $ ls $PYTHONPATH
    __pycache__  _openshot.pyd  cmake_install.cmake  CMakeFiles  libopenshot.dll  libopenshot-audio.dll  Makefile  openshot.py  pyopenshot_autogen

It's looking to me now like not only the library DLLs, but all of their library DEPENDENCIES, have to be gathered together in the same directory. So, you'll probably want to install OpenShot from a Windows installer, then look at the contents of C:\Program Files\OpenShot Video Editor*\lib\. Any DLL in there is likely going to be needed in order to successfully import _openshot. (But if you're missing a DLL, you should at least be able to unsuccessfully import it with import _openshot, and a least get a different error that there's a missing DLL, not that the entire module can't be found.)

I wish I could be more help, but I don't build OpenShot on Windows myself, and only run it at all in a Windows VM on my Linux box when I need to debug something, so I'm not super familiar with Python's Windows (and, separately, MSYS/MinGW) quirks.

(Plus our own packaging quirks. I only just realized that we don't even package the Python code, just the compiled .pyc files (zipped into a library.zip file with lots of other Python module binaries), so unless you have the same version of Python installed that OpenShot uses, you can't even run the .py bits of OpenShot from the install because the binaries aren't compatible.)

ferdnyc commented 4 years ago

@mkarg Did you ever manage to get this working, or at least make any further progress?

mkarg commented 4 years ago

@mkarg Did you ever manage to get this working, or at least make any further progress?

Sorry for not being responsive for some days, and thanks again for your kind help! Actually I am out of office this week, so I had no chance to try most of your tips. What definitively did not work is copying the libopenshot.dll and libopenshot-audio.dll into a full installation of OpenShot -- Windows complains "Cannot load the module" then. I need to setup a C mock which simply does LoadLibrary and GetLastError to find out what problem Windows actually has and which module it means. Once that is investigated, I will report here. :-)

mkarg commented 4 years ago

Using Dependecy Walker I found out which DLLs I had to replace by a later version (I will post the list later when everything is running). Now Dependency Walker shows the same output for both, the original libopenshot.dll 2.4.4, and my self-built one. As a result, the original full-installed openshot.exe 2.4.4 doesn't complain anymore about missing module (which is great!) but now about a missing procedure (unfortunately it is unclear which one). So it seems, I definitively have to write a C mock now. Stay tuned. :-)

ferdnyc commented 4 years ago

@mkarg

I have a PR open in OpenShot (OpenShot/openshot-qt#3106) that adds a terminal-enabled launcher to the OpenShot distribution, there's an installer build linked in a comment there. Running that, instead of the graphical launcher, might show some useful messages in the terminal output. (Might not, but worth a try.)

You can run it from a Windows Command prompt (or PowerShell, I assume) to avoid the terminal window auto-closing when the process terminates.

mkarg commented 4 years ago

@ferdnyc Sorry for the long delay!

I have a PR open in OpenShot (OpenShot/openshot-qt#3106) that adds a terminal-enabled launcher to the OpenShot distribution, there's an installer build linked in a comment there. Running that, instead of the graphical launcher, might show some useful messages in the terminal output. (Might not, but worth a try.)

Thanks a lot for that CLI launcher! This helps a lot with development.

I reinstalled using the installer build linked in that comment of yours, then git pulled libopenshot-qt's latest source code, cleaned the build folder, and made a complete build. Then I copied the resulting libopenshot.dll into that 2.4.4-dev2 installation your installer created on disk. Unfortunately it still does not work :cry:. The CLI does not say much more than what we already knew before: It does not find "some" procedure (but which?):

$ ./openshot-qt-cli.exe
Loaded modules from current directory: C:/Program Files/OpenShot Video Editor
         app:INFO ------------------------------------------------
         app:INFO             Fri Jan  3 18:54:09 2020
         app:INFO               Starting new session
Traceback (most recent call last):
  File "C:\msys64\mingw64\lib\python3.7\site-packages\cx_Freeze\initscripts\__startup__.py", line 14, in run
  File "C:\msys64\mingw64\lib\python3.7\site-packages\cx_Freeze\initscripts\Console.py", line 26, in run
  File "openshot_qt/launch.py", line 103, in <module>
  File "openshot_qt/launch.py", line 96, in main
  File "C:\Program Files\OpenShot Video Editor\classes\app.py", line 72, in __init__
    from classes import settings, project_data, updates, language, ui_util, logger_libopenshot
  File "C:\Program Files\OpenShot Video Editor\classes\logger_libopenshot.py", line 31, in <module>
    import openshot
  File "C:\Users\Administrator\builds\7546b651\0\OpenShot\openshot-qt\openshot.py", line 15, in <module>
ImportError: DLL load failed: Die angegebene Prozedur wurde nicht gefunden.
         app:INFO             OpenShot's session ended
         app:INFO             Fri Jan  3 18:54:54 2020
         app:INFO ================================================

(The German error text means "The given procedure was not found")

Apparently the Python code tries to find a function in the DLL but does not find it, but I don't know how to find out which function that is. Line 15 in openshot.py looks like this:

    import _openshot

Apparently there is no _openshot.py source file, but just a _openshot.pyd file, so I cannot look into that file.

Update: Apparently this is a side effect of your _openshot.pyd containing lots more methods than mine (compiled today from develop), e. g. _ZN8openshot8Keyframe11GetMaxPointEv: image. So I also copied my _openshot.pyd to the install directory (including libpython3.8.dll as this is what my DLL apparently wants). But now the CLI launcher says this:

$ ./openshot-qt-cli.exe
Loaded modules from current directory: C:/Program Files/OpenShot Video Editor
         app:INFO ------------------------------------------------
         app:INFO             Sat Jan  4 20:27:29 2020
         app:INFO               Starting new session
Segmentation fault

sigh :cry:

ferdnyc commented 4 years ago

@ferdnyc Sorry for the long delay!

@mkarg Same! Not sure how I missed this for three days. On the plus side, I think you're really close.

Update: Apparently this is a side effect of your _openshot.pyd containing lots more methods than mine (compiled today from develop),

The installer you downloaded is a few weeks old, that difference can be chalked up to changes that have been merged since then. But, really, it shouldn't matter because if all goes right you'll have built a new libopenshot.dll, a new _openshot.pyd, and a new openshot.py all from the same source tree and in sync with each other.

If they're NOT in sync, and a piece is looking for components that another doesn't have, then one or more of those three files must be left from the older build that was packaged with the installer.

When you build the entire source tree for libopenshot, you should end up with a libopenshot.dll in the src/ dir of your build tree, and both openshot.py and _openshot.pyd in src/bindings/python/ (again, in the build dir.) All three need to be copied into OpenShot.

None of the openshot-qt code would affect the DLL loading process like that, even if it was trying to call a missing method you'd get a different, Python-based traceback. The failure to resolve the C++ binding symbols has to stem from a mismatch between the DLL and the Swig-generated Python extension/module.

It's also possible that one of those pieces is inside a zip file in the OpenShot install, I'd suggest checking inside those and deleting any contents that match files you're replacing from your build. (In the zip file the module may be stored in bytecompiled form as openshot.pyc, you'd want to delete that too.)

ferdnyc commented 4 years ago

Actually, the libpython3.8.dll issue you mentioned may be a problem as well, since I'm not sure the Python 3.7 executable bundled with the OpenShot installer will load an extension linked with Python 3.8 libs. You may need to downgrade your MSYS2 environment (which I think you're using, right? Sorry, on my phone) to the Python 3.7 interpreter and library packages, and compile the extension against those.

On the bright side, pacman should make that pretty easy, I can't imagine they don't still have python3.7 in the repos.

ferdnyc commented 4 years ago

Oh, also, with the merge of OpenShot/openshot-qt#3106 the CLI launcher should now be included in the regular Daily Build installers as well, so if you want to download a build with a libopenshot.dll that matches the one you're building you can just grab the latest official dev installer. (The bindings will still still be linked with Python 3.7, though.)

mkarg commented 4 years ago

@ferdnyc Thank you so much, your help is really outstanding!

Oh, also, with the merge of OpenShot/openshot-qt#3106 the CLI launcher should now be included in the regular Daily Build installers as well, so if you want to download a build with a libopenshot.dll that matches the one you're building you can just grab the latest official dev installer. (The bindings will still still be linked with Python 3.7, though.)

That actually solved my most immediate problem -- I now can build the DLL, copy just it into the 2.4.5-RC installation, and everything runs well. :tada:

Next issue I have to solve is how to downgrade MSYS2's Python3 from 3.8 to 3.7 to be able to also use my _openshot.pyd and openshot.py files:

Actually, the libpython3.8.dll issue you mentioned may be a problem as well, since I'm not sure the Python 3.7 executable bundled with the OpenShot installer will load an extension linked with Python 3.8 libs. You may need to downgrade your MSYS2 environment (which I think you're using, right? Sorry, on my phone) to the Python 3.7 interpreter and library packages, and compile the extension against those. On the bright side, pacman should make that pretty easy, I can't imagine they don't still have python3.7 in the repos.

In fact, I cannot find a parameter for pacman where I could pass the version for a package.

BTW, wouldn't it be better if the 2.4.5-RC setup would be built using Python 3.8, too? I mean, because it is the default pacman installs, so following the original OpenShot build instructions on Windows, you definitively will have 3.8, not 3.7.

Update: Managed to downgrade from Python 3.8 to Python 3.7, rebuilt DLL and PYD, copied it into the 2.4.5-RC setup folder and it all works perfectly well. Thank you so much! :+1:

Update: Here is how to downgrade Python 3.8 to Python 3.7 in MSYS2:

curl -O http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-python3-3.7.5-1-any.pkg.tar.xz
pacman -U mingw-w64-x86_64-python3-3.7.5-1-any.pkg.tar.xz

Update: Added optional downgrading steps to Windows Build Instructions.

mkarg commented 4 years ago

Added additional steps and corrected paths to Windows Build Instructions, so this should work fine now. If not, please reopen this issue. :-)

ferdnyc commented 4 years ago

Excellent, glad you sorted it out! I was coming here to post basically that, since I had some time to poke around in Windows and eventually arrived at the same solution.

On the bright side, pacman should make that pretty easy, I can't imagine they don't still have python3.7 in the repos.

In fact, I cannot find a parameter for pacman where I could pass the version for a package.

Yeah, I'm really not sure there is one... I can't seem to find any documentation about it, at least. Which would be a surprising oversight, from the Arch toolsmiths, as they're usually all about user control.

It also doesn't make sense, then, that all of the old versions of packages would still be up in the download area like that. There's no point in doing that except if it's still possible to access them through pacman, I'd think. I feel like we must be missing something on that front. That they're there for people to manually download and install doesn't seem like the full story.

But, actually, the fact that you were able to manually downgrade still doesn't really count as keeping Python 3.7 available, not in the sense that I meant. And I have to say I'm disappointed in the MSYS folks. When I said "I can't imagine they don't still have python3.7 in the repos.", what I meant was something more like the Fedora setup.

Fedora's default Python right now is Python 3.7. You install "python" or "python3", that's what you get. But they know that people have extensions compiled for different versions, or code that only works with certain versions. So, there are packages for every other available version of Python in the repos, separate from Python 3.7, that can all be installed at the same time:

$ sudo dnf list python3\*|egrep 'python3[0-9]'|cut -c1-75
python34.x86_64                                           3.4.10-6.fc31    
python35.x86_64                                           3.5.9-1.fc31     
python36.x86_64                                           3.6.10-1.fc31    
python38.x86_64                                           3.8.1-1.fc31     
python34.i686                                             3.4.10-6.fc31    
python35.i686                                             3.5.9-1.fc31     
python36.i686                                             3.6.10-1.fc31    
python38.i686                                             3.8.1-1.fc31     
python39.i686                                             3.9.0~a2-1.fc31  
python39.x86_64                                           3.9.0~a2-1.fc31  

Installing python38.x86_64 will get you an interpreter named python3.8, that loads packages from /usr/lib64/python3.8/. python34.x86_64 uses /usr/lib/python3.4/. Any or all can be installed without having to remove or affect python a.k.a python3 a.k.a python3.7.

There's no reason MSYS2/MinGW shouldn't offer the same flexibility. (Then again, there's no reason you shouldn't have been able to downgrade right from pacman. Well, except that they renamed their Python packages from python3 back to python just a week or so ago. Which made things even more confusing, because it appears at first glance like mingw-w64-x86_64-python version 3.8.1 or whatever is the only version in the repo.)