1#!/usr/bin/env python
2
3# install.py tool to do a generic build of a library
4# soft linked to by many of the lib/Install.py files
5# used to automate the steps described in the corresponding lib/README
6
7from __future__ import print_function
8import sys,os,subprocess
9import glob
10
11sys.path.append('..')
12from install_helpers import checkmd5sum
13
14# help message
15
16help = """
17Syntax from src dir: make lib-libname args="-m machine -e suffix"
18Syntax from lib dir: python Install.py -m machine -e suffix
19
20libname = name of lib dir (e.g. atc, h5md, meam, poems, etc)
21specify -m and optionally -e, order does not matter
22
23  -m = peform a clean followed by "make -f Makefile.machine"
24       machine = suffix of a lib/Makefile.* file
25  -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix
26       does not alter existing Makefile.machine
27
28Examples:
29
30make lib-poems args="-m serial" # build POEMS lib with same settings as in the serial Makefile in src
31make lib-colvars args="-m mpi"  # build COLVARS lib with same settings as in the mpi Makefile in src
32make lib-meam args="-m ifort"   # build MEAM lib with custom Makefile.ifort (using Intel Fortran)
33"""
34
35# settings
36
37version = "1.2.9"
38url = "https://github.com/MolSSI-MDI/MDI_Library/archive/v%s.tar.gz" % version
39
40# known checksums for different MDI versions. used to validate the download.
41checksums = { \
42              '1.2.7' : '2f3177b30ccdbd6ae28ea3bdd5fed0db', \
43              '1.2.9' : 'ddfa46d6ee15b4e59cfd527ec7212184', \
44              }
45
46# print error message or help
47
48def error(str=None):
49  if not str: print(help)
50  else: print("ERROR",str)
51  sys.exit()
52
53  # expand to full path name
54# process leading '~' or relative path
55
56def fullpath(path):
57  return os.path.abspath(os.path.expanduser(path))
58
59def which(program):
60  def is_exe(fpath):
61    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
62
63  fpath, fname = os.path.split(program)
64  if fpath:
65    if is_exe(program):
66      return program
67  else:
68    for path in os.environ["PATH"].split(os.pathsep):
69      path = path.strip('"')
70      exe_file = os.path.join(path, program)
71      if is_exe(exe_file):
72        return exe_file
73
74  return None
75
76def geturl(url,fname):
77  success = False
78
79  if which('curl') != None:
80    cmd = 'curl -L -o "%s" %s' % (fname,url)
81    try:
82      subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
83      success = True
84    except subprocess.CalledProcessError as e:
85      print("Calling curl failed with: %s" % e.output.decode('UTF-8'))
86
87  if not success and which('wget') != None:
88    cmd = 'wget -O "%s" %s' % (fname,url)
89    try:
90      subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
91      success = True
92    except subprocess.CalledProcessError as e:
93      print("Calling wget failed with: %s" % e.output.decode('UTF-8'))
94
95  if not success:
96    error("Failed to download source code with 'curl' or 'wget'")
97  return
98
99# parse args
100
101args = sys.argv[1:]
102nargs = len(args)
103if nargs == 0: error()
104
105machine = None
106extraflag = 0
107
108iarg = 0
109while iarg < nargs:
110  if args[iarg] == "-m":
111    if iarg+2 > nargs: error()
112    machine = args[iarg+1]
113    iarg += 2
114  elif args[iarg] == "-e":
115    if iarg+2 > nargs: error()
116    extraflag = 1
117    suffix = args[iarg+1]
118    iarg += 2
119  else: error()
120
121# set lib from working dir
122
123cwd = os.getcwd()
124lib = os.path.basename(cwd)
125
126# download and unpack MDI_Library tarball
127
128homepath = "."
129homedir = "%s/MDI_Library" % homepath
130
131print("Downloading MDI_Library ...")
132mditar = "%s/v%s.tar.gz" % (homepath,version)
133geturl(url, mditar)
134
135# verify downloaded archive integrity via md5 checksum, if known.
136if version in checksums:
137  if not checkmd5sum(checksums[version], mditar):
138    sys.exit("Checksum for MDI library does not match")
139
140print("Unpacking MDI_Library tarball ...")
141if os.path.exists("%s/v%s" % (homepath,version)):
142  cmd = 'rm -rf "%s/v%s"' % (homepath,version)
143  subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
144cmd = 'cd "%s"; tar -xzvf v%s.tar.gz' % (homepath,version)
145subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
146os.remove("%s/v%s.tar.gz" % (homepath,version))
147if os.path.basename(homedir) != version:
148  if os.path.exists(homedir):
149    cmd = 'rm -rf "%s"' % homedir
150    subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
151  os.rename("%s/MDI_Library-%s" % (homepath,version),homedir)
152
153# create Makefile.auto as copy of Makefile.machine
154# reset EXTRAMAKE if requested
155
156if not os.path.exists("Makefile.%s" % machine):
157  error("lib/%s/Makefile.%s does not exist" % (lib,machine))
158
159lines = open("Makefile.%s" % machine,'r').readlines()
160fp = open("Makefile.auto",'w')
161
162has_extramake = False
163for line in lines:
164  words = line.split()
165  if len(words) == 3 and words[0] == "EXTRAMAKE" and words[1] == '=':
166    has_extramake = True
167    if extraflag:
168      line = line.replace(words[2],"Makefile.lammps.%s" % suffix)
169  fp.write(line)
170
171fp.close()
172
173# make the library via Makefile.auto optionally with parallel make
174
175try:
176  import multiprocessing
177  n_cpus = multiprocessing.cpu_count()
178except:
179  n_cpus = 1
180
181print("Building lib%s.so ..." % lib)
182cmd = "make -f Makefile.auto clean; make -f Makefile.auto -j%d" % n_cpus
183txt = subprocess.check_output(cmd,shell=True,stderr=subprocess.STDOUT)
184print(txt.decode('UTF-8'))
185
186# create 2 links in lib/mdi to MDI Library src dir
187
188print("Creating links to MDI Library include and lib files")
189if os.path.isfile("includelink") or os.path.islink("includelink"):
190  os.remove("includelink")
191if os.path.isfile("liblink") or os.path.islink("liblink"):
192  os.remove("liblink")
193os.symlink(os.path.join(homedir, 'MDI_Library'), 'includelink')
194os.symlink(os.path.join(homepath, 'build', 'MDI_Library'), 'liblink')
195
196# Append the -rpath option to Makefile.lammps
197
198dir_path = os.path.dirname(os.path.realpath(__file__))
199rpath_option = "-Wl,-rpath=" + str(dir_path) + "/liblink"
200makefile_lammps = open(str(dir_path) + "/Makefile.lammps", "a")
201makefile_lammps.write(str(rpath_option) + "\n")
202makefile_lammps.close()
203
204
205shared_files = glob.glob( os.path.join( homepath, "liblink", "lib%s.so*" % lib) )
206if len(shared_files) > 0:
207  print("Build was successful")
208else:
209  error("Build of lib/%s/lib%s.so was NOT successful" % (lib,lib))
210if has_extramake and not os.path.exists("Makefile.lammps"):
211  print("lib/%s/Makefile.lammps was NOT created" % lib)
212