File: install.py

package info (click to toggle)
lammps 20251210%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 465,808 kB
  • sloc: cpp: 1,031,565; python: 26,771; ansic: 8,808; f90: 7,302; sh: 5,316; perl: 4,171; fortran: 2,442; xml: 1,613; makefile: 1,119; objc: 238; lisp: 188; yacc: 58; csh: 16; awk: 14; tcl: 6; javascript: 2
file content (168 lines) | stat: -rw-r--r-- 6,948 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env python

"""
Script to build a "binary wheel" for the 'pip' Python package manager for
the LAMMPS python module which includes the shared library file. After a
successful build the script attempts to install the wheel into a system
specific site-packages folder or - failing that - into the corresponding
user site-packages folder.  Called from the 'install-python' build target
in the GNU make and CMake based build systems.  Can also be called
independently and used to build the wheel without installing it.
"""

from __future__ import print_function
import sys, os, shutil, glob, subprocess
from argparse import ArgumentParser

parser = ArgumentParser(prog='install.py',
                        description='LAMMPS python package installer script')

parser.add_argument("-p", "--package", required=True,
                    help="path to the LAMMPS Python package folder")
parser.add_argument("-l", "--lib", required=True,
                    help="path to the compiled LAMMPS shared library")
parser.add_argument("-n", "--noinstall", action="store_true", default=False,
                    help="only build a binary wheel. Don't attempt to install it")
parser.add_argument("-w", "--wheeldir", required=False,
                    help="path to a directory where the created wheel will be stored")
parser.add_argument("-v", "--versionfile", required=True,
                    help="path to the LAMMPS version.h source file")
parser.add_argument("-f", "--force", action="store_true", required=False, default=False,
                    help="force installation of LAMMPS Python package")

args = parser.parse_args()

# validate arguments and make paths absolute

if args.package:
  if not os.path.exists(args.package):
    print("\nERROR: LAMMPS package folder %s does not exist\n" % args.package)
    parser.print_help()
    sys.exit(1)
  else:
    args.package = os.path.abspath(args.package)
    if ((os.path.basename(args.package) != "lammps")
        and ((os.path.basename(os.path.dirname(args.package)) != "python"))):
             print("\nERROR: LAMMPS package folder path %s does not end in %s\n"
                   % (args.package, os.path.join("python", "lammps")))
             parser.print_help()
             sys.exit(1)

if args.lib:
  if not os.path.exists(args.lib):
    print("\nERROR: LAMMPS shared library %s does not exist\n" % args.lib)
    parser.print_help()
    sys.exit(1)
  else:
    args.lib = os.path.abspath(args.lib)

if args.wheeldir:
  if not os.path.exists(args.wheeldir):
    print("\nERROR: directory %s to store the wheel does not exist\n" % args.wheeldir)
    parser.print_help()
    sys.exit(1)
  else:
    args.wheeldir = os.path.abspath(args.wheeldir)

if args.versionfile:
  if not os.path.exists(args.versionfile):
    print("\nERROR: LAMMPS version file at %s does not exist\n" % args.versionfile)
    parser.print_help()
    sys.exit(1)
  else:
    args.versionfile = os.path.abspath(args.versionfile)

olddir = os.path.abspath('.')
pythondir = os.path.abspath(os.path.join(args.package,'..'))
os.putenv('LAMMPS_VERSION_FILE',os.path.abspath(args.versionfile))

# purge old build folder
if os.path.isdir(os.path.join(olddir, 'build-python')):
  print("Cleaning old build directory")
  shutil.rmtree(os.path.join(olddir, 'build-python'))

# remove any old wheel files left over from previous calls
print("Purging existing wheels...")
for wheel in glob.glob('lammps-*.whl'):
  print("deleting " + wheel)
  os.remove(wheel)

# copy python tree to build folder
builddir = shutil.copytree(pythondir, os.path.join(olddir, 'build-python'))
os.chdir(builddir)

# copy shared object to the current folder so that
# it will show up in the installation at the expected location
os.putenv('LAMMPS_SHARED_LIB',os.path.basename(args.lib))
shutil.copy(args.lib,'lammps')

# create a virtual environment for building the wheel
shutil.rmtree('buildwheel', True)
try:
  txt = subprocess.check_output([sys.executable, '-m', 'venv', 'buildwheel'], stderr=subprocess.STDOUT, shell=False)
  print(txt.decode('UTF-8'))
except subprocess.CalledProcessError as err:
  sys.exit("Failed to create a virtual environment: {0}".format(err.output.decode('UTF-8')))

# now run the commands to build the wheel. those must be in a separate script
# and run in subprocess, since this will use the virtual environment and
# there is no simple way to return from that in python.
os.system(sys.executable + ' makewheel.py')

# copy wheel to final location
for wheel in glob.glob('lammps-*.whl'):
  if args.wheeldir:
    shutil.copy(wheel, args.wheeldir)
  else:
    shutil.copy(wheel, olddir)

# remove temporary folders and files
os.chdir(olddir)
shutil.rmtree('build-python', True)

# stop here if we were asked not to install the wheel we created
if args.noinstall:
  exit(0)

# install the wheel with pip. first try to install in the default environment.
# that will be a virtual environment, if active, or the system folder.
# if in a virtual environment, we must not use the python executable
# that is running this script (configured by cmake), but use "python"
# from the regular system path. The user may have changed to the virtual
# environment *after* running cmake.
# recent versions of pip will automatically drop to use the user folder
# in case the system folder is not writable.

# we use a subprocess so we can catch an exception on failure.
# we need to check whether pip refused to install because of a
# version of the module previously installed with distutils. those
# must be uninstalled manually. We must not ignore this and drop
# back to install into a (forced) user folder.

if "VIRTUAL_ENV" in os.environ:
  print("Installing wheel into virtual environment")
  py_exe = 'python'
else:
  print("Installing wheel into system site-packages folder")
  py_exe = sys.executable

try:
  if args.force:
    txt = subprocess.check_output([py_exe, '-m', 'pip', 'install', '--force-reinstall', '--break-system-packages', wheel], stderr=subprocess.STDOUT, shell=False)
  else:
    txt = subprocess.check_output([py_exe, '-m', 'pip', 'install', '--force-reinstall', wheel], stderr=subprocess.STDOUT, shell=False)
  print(txt.decode('UTF-8'))
  sys.exit(0)
except subprocess.CalledProcessError as err:
  errmsg = err.output.decode('UTF-8')
  if errmsg.find("distutils installed"):
    sys.exit(errmsg + "You need to uninstall the LAMMPS python module manually first.\n")
try:
  print('Installing wheel into system site-packages folder failed. Trying user folder now')
  if args.force:
    txt = subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--user', '--force-reinstall', '--break-system-packages', wheel], stderr=subprocess.STDOUT, shell=False)
  else:
    txt = subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--user', '--force-reinstall', wheel], stderr=subprocess.STDOUT, shell=False)
  print(txt.decode('UTF-8'))
except:
  sys.exit('Failed to install wheel ' + wheel)