nrn icon indicating copy to clipboard operation
nrn copied to clipboard

Windows native build

Open alexsavulescu opened this issue 3 years ago • 28 comments

Even if this will be exploratory only, at least it will provide insight into the things that are not portable (i.e. shell scripts driven through CMake)

Resources:

  • https://github.com/neuronsimulator/nrn/issues/623
  • https://github.com/neuronsimulator/nrn/blob/master/.github/workflows/windows.yml
  • https://github.com/neuronsimulator/nrn/issues/319 (TL;DNR How to build with MinGW, best to follow scripts from CI. Might provide some useful information)

alexsavulescu avatar Mar 20 '23 14:03 alexsavulescu

This is not yet functional and will probably require enabling a lot more #ifdefs

Current WIP is in:

  • NRN: https://github.com/neuronsimulator/nrn/tree/fenster-neu-bauen
  • IV: https://github.com/neuronsimulator/iv/tree/mehr-fenster-neu-bauen

These branches allow to build NEURON, albeit currently the configuration files are not found. Areas of work:

  • [ ] Disable readline properly, replace with the windows-ish equivalent mentioned below
  • [x] Replace getopt, which is not easily available on windows with CLI11 if possible
  • [x] Build with Microsoft's MPI
  • [ ] Build with more features
  • [ ] Make configuration stuff work to actually run things.
  • [ ] WIN32 is a bad macro, prefer _WIN32, and use MSVC in CMake
  • [x] Make sure checkmarks in IV occur at the right place, not the bottom left of the window

To use these branches, I worked in VirtualBox with the following Vagrantfile:

Vagrant.configure("2") do |config|
  config.vm.box = "gusztavvargadr/windows-10"
end

Use it with

vagrant up
vagrant ssh

This gave me a preconfigured Windows 10 with choco already available.

I then installed the following packages (my own convenience utilities included):

PS C:\Users\vagrant\nrn> choco list -l
Chocolatey v1.4.0
chocolatey 1.4.0
chocolatey-compatibility.extension 1.0.0
chocolatey-core.extension 1.4.0
chocolatey-dotnetfx.extension 1.0.1
chocolatey-visualstudio.extension 1.11.1
chocolatey-windowsupdate.extension 1.0.5
cmake.install 3.27.6
dotnetfx 4.8.0.20220524
fd 8.7.0
getopt 2.14.1
gh 2.35.0
git 2.42.0
git.install 2.42.0
KB2919355 1.0.20160915
KB2919442 1.0.20160915
KB2999226 1.0.20181019
KB3033929 1.0.5
KB3035131 1.0.3
neovim 0.9.2
openssh 8.0.0.1
python 3.11.0
python3 3.11.0
ripgrep 13.0.0.20220913
sed 4.9
vcredist140 14.36.32532
vcredist2015 14.0.24215.20170201
visualstudio-installer 2.0.3
visualstudio2019-workload-nativedesktop 1.0.1
visualstudio2019community 16.11.30.0
visualstudio2022community 117.7.4.0
winflexbison 2.4.9.20170215
31 packages installed.

Configured paths in Powershell with:

$env:Path += ";C:\tools\neovim\nvim-win64\bin;C:\Python311\;C:\Program Files\CMake\bin\;C:\Program Files\Git\bin\;C:\Program Files\GitHub CLI;C:\Python311\Scripts"
$env:PATH += ";C:\ProgramData\chocolatey\lib\ripgrep\tools\ripgrep-13.0.0-x86_64-pc-windows-msvc\;"
$env:PATH += ";C:\ProgramData\chocolatey\lib\sed\tools\;"
$env:PATH += ";C:\ProgramData\chocolatey\lib\fd\tools\fd-v8.7.0-x86_64-pc-windows-msvc\;"

After cloning Neuron, I was able to configure with:

cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=C:\Python311\python.exe -DBISON_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison\tools\win_bison.exe -D FLEX_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison\tools\win_flex.exe -DNRN_ENABLE_MPI=OFF

And build with:

cmake --build build --config Release

(release config required to avoid trying to link to a debug Python)

matz-e avatar Sep 28 '23 13:09 matz-e

Progress: image

matz-e avatar Sep 29 '23 13:09 matz-e

This is great! I'd like to follow along with a virtual box windows guest and, if I can, contribute to the development. I gather you are working in a powershell with no msys or mingw installed. I don't know what vagrant is but will look it up. Is the main prerequisite to everything an installation of visual c?

I think I have the overall idea now. Following your above instructions, I end up with vagrant ssh just exiting to my starting shell.

hines@hines-t7500:~/neuron/winvagrant$ vagrant ssh
<internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require': cannot load such file -- winrm (LoadError)
	from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/plugins/communicators/winrm/shell.rb:9:in `block in <top (required)>'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/util/silence_warnings.rb:8:in `silence!'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/plugins/communicators/winrm/shell.rb:8:in `<top (required)>'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/plugins/communicators/winrm/communicator.rb:6:in `require_relative'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/plugins/communicators/winrm/communicator.rb:6:in `<top (required)>'
	from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/plugins/communicators/winrm/plugin.rb:15:in `block in <class:Plugin>'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/registry.rb:27:in `get'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/machine.rb:267:in `communicate'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/machine.rb:149:in `initialize'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/vagrantfile.rb:81:in `new'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/vagrantfile.rb:81:in `machine'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/environment.rb:716:in `machine'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/plugin/v2/command.rb:180:in `block in with_target_vms'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/plugin/v2/command.rb:213:in `block in with_target_vms'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/plugin/v2/command.rb:212:in `map'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/plugin/v2/command.rb:212:in `with_target_vms'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/plugins/commands/ssh/command.rb:46:in `execute'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/cli.rb:67:in `execute'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/lib/vagrant/environment.rb:290:in `cli'
	from /usr/share/rubygems-integration/all/gems/vagrant-2.2.19/bin/vagrant:226:in `<top (required)>'
	from /usr/bin/vagrant:25:in `load'
	from /usr/bin/vagrant:25:in `<main>'
hines@hines-t7500:~/neuron/winvagrant$ cat Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "gusztavvargadr/windows-10"
end

I guess I did not vagrant box add gusztavvargadr/windows-10

nrnhines avatar Sep 29 '23 19:09 nrnhines

I just chose vagrant because that was recommended to me :)

Did you do a vagrant up first? For me, that downloads all the required glue, configures and starts everything, and then also shows the Windows virtual machine in the VirtualBox GUI. Then I could ssh into the machine, and manually call powershell to start working.

To get the GUI in the screenshot above, I just launched the visual interface from VirtualBox.

matz-e avatar Oct 02 '23 10:10 matz-e

Vagrant seems useful but I haven't been successful with it so far. However, with the manual virtualbox guest of windows11 I did successfully build your branch and the classical GUI works. Seems there are only a few edges that need work such as hoc readline. My lack of familiarity with PowerShell is slowing me down. Do you by any chance know the correct syntax for choco install cython so that it gets the < 3 version? I'm curious if the vc build will fix our long-standing rxd issue of #1522 which has now re-occurred.

nrnhines avatar Oct 02 '23 12:10 nrnhines

I actually installed all the Python packages with py.exe -mpip install "cython<3" IIRC. The powershell should actually not be a requirement, but I find the difference to Linux less jarring than with the old Windows command line.

Another thing I omitted: to get the NRN GUI to display, I had to copy the DLLs into the same directory as the executable. There's probably some path setting I'm forgetting...

I somehow got the permutations of ifdef in IV right to fix the checkmarks currently.

matz-e avatar Oct 02 '23 20:10 matz-e

This century and some of the previous I used msys and cygwin. So I've always worked in a bash shell :)

had to copy the DLLs into the same directory as the executable

That is where they have always gone when creating a setup.exe. Sorry if you spent much time on that.

For visual c, is there anything corresponding to the much smaller mac command_line_tools (instead of the large xcode)? If so, I'm thinking the setup.exe can ask if the user would like to install it (needed for nrnivmodl). That would bring the nrn installer down to the size of the mac pkg installer and also simplify installation of wheels for python.

This is great, though. Looks like it will be possible to construct the windows setup.exe and wheels using analogies to similar files we already have for linux and mac.

nrnhines avatar Oct 02 '23 21:10 nrnhines

This is great, though. Looks like it will be possible to construct the windows setup.exe and wheels using analogies to similar files we already have for linux and mac.

Thanks, I hope that this will simplify things a little bit. In my opinion, the biggest hangup may be readline, which seems to be very linux-centric.

I thought that in the past I saw windows installers requesting to install certain parts of the Microsoft universe? Something to look into to keep the installer smaller; I think distributing any VS component would also entail a license-headache!

About the DLLs: I think we can have this such that a cmake --install build --config Release will work out of the box. That's maybe going to be what I'm looking into next.

My bash on the Windows comes from git, I'm not sure we can expect the user to have that around and in the path? More experimentation :)

matz-e avatar Oct 03 '23 07:10 matz-e

Regarding readline, I found this issue on the Python tracker: https://bugs.python.org/issue45870

The REPL shell and input() call PyOS_Readline(). If this call isn't hooked (e.g. by the readline module), and stdin is a console file, then it reads a line from the console via ReadConsoleW(). If the console's input stream is configured in line-input mode, which we assume it is, this function provides basic readline-ish support, including a line editor that supports input history and aliases. The history is stored in an in-memory buffer in the console, which doesn't get save and reused across console sessions. There is no public API to get the history contents, and there is no support at all to set it.

I think this may be worth looking into?

matz-e avatar Oct 05 '23 07:10 matz-e

That python issue has an interesting discussion.

ReadConsoleW(). ... this function provides basic readline-ish support

seems like we might be happy with it as the simplest fix. It's got to be simpler than looking into the third party pyreadline module, or supplying our own libreadline.dll (built with msys2? I presume libreadline cannot be build with msvc).

nrnhines avatar Oct 05 '23 11:10 nrnhines

I tried my hand at building with mpi and rx3d

PS C:\Users\micha\neuron\nrn> cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=E:\Python311\python.exe -DBISON_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison\tools\win_bison.exe -DFLEX_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison\tools\win_flex.exe -DNRN_ENABLE_MPI=ON -DNRN_ENABLE_RX3D=ON -DCMAKE_INSTALL_PREFIX=c:\marshalnrn\nrn -DNRN_ENABLE_PYTHON_DYNAMIC=ON -DNRN_PYTHON_DYNAMIC="e:/python11/python" -DNRN_ENABLE_MPI_DYNAMIC=ON -DCMAKE_PREFIX_PATH="c:\ms-mpi"
PS C:\Users\micha\neuron\nrn> cmake --build build --config Release

and getting the error

  Generating help_data.dat
  The system cannot find the path specified.
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(247,5): e
rror MSB8066: Custom build for 'C:\Users\micha\neuron\nrn\build\CMakeFiles\040d403017507bddc7eb0bf05e6e04e8\help_data_d
at.rule' exited with code 3. [C:\Users\micha\neuron\nrn\build\help_data_dat.vcxproj]

After looking in nrn/CMakeLists.txt for how help_data.dat is built, the followng manual command was successful in creating it.

PS C:\Users\micha\neuron\nrn> e:/python311/python c:/users/micha/neuron/nrn/docs/parse_rst.py c:/users/micha/neuron/nrn/docs/python c:/users/micha/neuron/nrn/build/lib/python/neuron/help_data.dat
PS C:\Users\micha\neuron\nrn\build\lib\python\neuron> ls

    Directory: C:\Users\micha\neuron\nrn\build\lib\python\neuron

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           10/7/2023  5:58 AM            115 _config_params.py
-a---           10/7/2023  6:36 AM         200648 help_data.dat

But still no luck with

PS C:\Users\micha\neuron\nrn> cmake --build build --config Release
MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  Checking File Globs
  Copying C:/Users/micha/neuron/nrn/share/demo to C:/Users/micha/neuron/nrn/build/share/nrn/demo
  Copying C:/Users/micha/neuron/nrn/share/lib to C:/Users/micha/neuron/nrn/build/share/nrn/lib
  Copying headers to build directory
  Generating help_data.dat
  The system cannot find the path specified.
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(247,5): e
rror MSB8066: Custom build for 'C:\Users\micha\neuron\nrn\build\CMakeFiles\040d403017507bddc7eb0bf05e6e04e8\help_data_d
at.rule' exited with code 3. [C:\Users\micha\neuron\nrn\build\help_data_dat.vcxproj]
  Update hh.mod for CoreNEURON compatibility
  interviews.vcxproj -> C:\Users\micha\neuron\nrn\build\lib\Release\interviews.lib
  nrngnu.vcxproj -> C:\Users\micha\neuron\nrn\build\lib\Release\nrngnu.lib
  sparse13.vcxproj -> C:\Users\micha\neuron\nrn\build\lib\Release\sparse13.lib
  rxdmath.vcxproj -> C:\Users\micha\neuron\nrn\build\bin\Release\rxdmath.dll
PS C:\Users\micha\neuron\nrn>

I'm at a loss as to how to get past this.

edit: The issue is perhaps related to -DNRN_ENABLE_PYTHON_DYNAMIC=ON as it disappears when that is OFF.

nrnhines avatar Oct 07 '23 14:10 nrnhines

rx3d will require more work from the Python side, too. Everything that Python tries to load via CDLL has to be marked as exported with the right DLL attributes.

matz-e avatar Oct 09 '23 11:10 matz-e

Just wondering if it's worth keeping help_data.dat, since now we have "extensive" documentation. It crawls itself up to setuptools & testing, and requires extra attention, maybe worth dropping it altogether. I have never ever heard anyone talking about it, except @ramcdougal :)

alexsavulescu avatar Oct 09 '23 22:10 alexsavulescu

the biggest hangup may be readline, which seems to be very linux-centric.

@matz-e maybe a stretch here, but I believe there are "modern" implementations in Rust that we could leverage? Surely you have the required experience to see things through

alexsavulescu avatar Oct 09 '23 22:10 alexsavulescu

@alexsavulescu what do you mean? helpdata.dat is what makes help work, e.g.:

help(h.xpanel)

ramcdougal avatar Oct 17 '23 18:10 ramcdougal

the biggest hangup may be readline, which seems to be very linux-centric.

@matz-e maybe a stretch here, but I believe there are "modern" implementations in Rust that we could leverage? Surely you have the required experience to see things through

I poked around "modern" implementations, and I'm not really convinced that they are that well maintained / popular. So far, I think the native Windows way should not be that much of a hassle.

OTOH, when just trying to run the OC console, I get to the point where we try to run

objref hoc_obj_[2]

and I get a parsing error:

hoc_oc caught exception: hoc_execerror: syntax error, unexpected NUMBER, expecting '\n'

(this is after upgrading bison to v3 and enabling some additional error output in parse.ypp)

matz-e avatar Oct 18 '23 13:10 matz-e

About this parsing error: I enabled more debug output: image

Generated by:

diff --git a/src/oc/hoc_oop.cpp b/src/oc/hoc_oop.cpp
index af1c88e7d..55bea2976 100644
--- a/src/oc/hoc_oop.cpp
+++ b/src/oc/hoc_oop.cpp
@@ -16,7 +16,7 @@
 #include "ocfunc.h"


-#define PDEBUG 0
+#define PDEBUG 1

 Symbol* nrnpy_pyobj_sym_{};
 #include "section.h"
@@ -45,6 +45,11 @@ void hoc_install_hoc_obj(void) {
     hoc_objectdata[s->u.oboff].pobj = pobj = (Object**) emalloc(sizeof(Object*));
     pobj[0] = nullptr;

+    auto const code0 = hoc_oc("sqrt((2.0))\n");
+    auto const code1 = hoc_oc("print sqrt((2.0))\n");
+    auto const code2 = hoc_oc("print \"a string\"\n");
+    auto const code3 = hoc_oc("print 7\n");
+    auto const code4 = hoc_oc("print 3.14\n");
     auto const code = hoc_oc("objref hoc_obj_[2]\n");
     assert(code == 0);
     hoc_obj_ = hoc_lookup("hoc_obj_");

It looks like printing a string works, but it breaks when printing numbers.

matz-e avatar Oct 18 '23 15:10 matz-e

@alexsavulescu what do you mean? helpdata.dat is what makes help work, e.g.:

help(h.xpanel)

I mean I have no recollection of anyone using the help in Python, except for you :)

alexsavulescu avatar Oct 19 '23 07:10 alexsavulescu

Correct, we use ?h.xpanel. The builtin help is extremely useful when offline. It's probably also used by tools to print docstrings and such.

1uc avatar Oct 19 '23 08:10 1uc

I would not want to miss docstrings, and I have to admit that I tend to use help() in Python quite a bit :)

matz-e avatar Oct 19 '23 08:10 matz-e

My impression is that standard python docstrings are widely used and we are trying to keep them up to date in the NEURON domain.

we use ?h.xpanel

I think some context will help in this regard. Back in 1993 I added the "?" nmodl syntax (along with comment strings containing blocks of lines beginning with 'help' in the c/c++ code. See grep -r '^help ' from nrn/src and grep -r '^\?' from nrn/share). That was to support an InterViews GUI help system that would be activated when the user pressed the NEURONMainMenu/help menu item. That would turn the cursor into a "?" and when the user navigated to a button and pressed it, an InterViews help text window would pop up to explain the purpose of the button. The text was organized as an outline and the user could navigate around and get some idea of the overall context. Much of that text still exists in https://nrn.readthedocs.io/en/latest/hoc/index.html and were called the "help" files. I think the elaborate shell scripts that supported construction and viewing are long since removed.

nrnhines avatar Oct 19 '23 12:10 nrnhines

?h.xpanel and help(h.xpanel) are different but equivalent views into helpdata

NMODL's ? and the defunct (?) GUI help are unrelated.

ramcdougal avatar Oct 19 '23 12:10 ramcdougal

?h.xpanel and help(h.xpanel) are different but equivalent views into helpdata

Thanks. My context wasn't sufficiently broad :)

nrnhines avatar Oct 19 '23 12:10 nrnhines

Yes, I'm sorry, misplaced irony, I'll restate my opinion without.

The Python help function which I've used in ipython via the shortcut ? has at times (never in the context of NEURON yet) allowed me to continue coding even without internet access. I'm merely adding myself to the list of people that have used help in Python, i.e. @ramcdougal isn't the only person using it.

1uc avatar Oct 19 '23 12:10 1uc

I've always used the RTD documentation. Not debating usefulness, just stating that this feature comes with a maintenance/CI cost.

alexsavulescu avatar Oct 19 '23 20:10 alexsavulescu

@nrnhines: do you have any intuition about parsing errors mentioned in https://github.com/neuronsimulator/nrn/issues/2293#issuecomment-1768729776? IIRC, Matthias was wondering if you can see something obvious.

pramodk avatar Oct 25 '23 10:10 pramodk

It looks like printing a string works, but it breaks when printing numbers.

Thought I'd work on this. Started by an attempt to build #2589 on my ubuntu desktop but immediately got stuck at the bizarre syntax error in the generated build/nmodlconf.h

/* Define to `int' if <sys/types.h> does not define. */
typedef  pid_t;

which generally gets generated as

/* Define to `int' if <sys/types.h> does not define. */ 
/* #undef pid_t */

This is a puzzle since the only difference between master and fenster-neu-bauen for nrn/cmake/ConfigFileSetting.cmake is

hines@hines-t7500:~/neuron/msvc$ git diff master -- cmake/ConfigFileSetting.cmake 
diff --git a/cmake/ConfigFileSetting.cmake b/cmake/ConfigFileSetting.cmake
index 668ea4454..b8a015bad 100644
--- a/cmake/ConfigFileSetting.cmake
+++ b/cmake/ConfigFileSetting.cmake
@@ -98,7 +98,7 @@ else()
   unset(NRNMECH_DLL_STYLE)
 endif()
 
-if(NRN_ENABLE_INTERVIEWS AND NOT MINGW)
+if(NRN_ENABLE_INTERVIEWS AND NOT MSVC)
   set(NRNOC_X11 1)
 else()
   set(NRNOC_X11 0)

Note

cmake version 3.27.7
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) 
$ cmake .. -G Ninja -DCMAKE_INSTALL_PREFIX=install -DPYTHON_EXECUTABLE=`which python3` -DNRN_ENABLE_RX3D=OFF -DCMAKE_BUILD_TYPE=Debug

nrnhines avatar Oct 25 '23 12:10 nrnhines

@nrnhines I'm sorry, that's a temporary windows hack, as something else does a proper typedef for pid_t and the current CMake magic broke for me.

I'll try to get some native Linux builds on that branch, too, to compare. Somehow had not thought of that. The pull request now has a nearly functional Windows build, it is just missing a bit of fiddling with the external definitions.

matz-e avatar Oct 25 '23 20:10 matz-e