Skip to content

Commit

Permalink
added loading of saved paths to utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Close committed Jan 27, 2017
1 parent 307ac6d commit ac62e6e
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 46 deletions.
15 changes: 15 additions & 0 deletions paths/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
The 'paths' directory contains the paths of utilities required in the code
generation process. They should be automatically generated by the installation
process but can be manually updated at a later stage if required.

The paths that can be set in this directory (as the contents of plain text
files with '_path' appended to the file name e.g. 'nrnivmodl_path') are:

* nrnivmodl
* modlunit
* nest-config

If a path file is not provided then the PATH environment variable will be
searched for the utility. Note that in this case it is important to double
check that the libninemlnrn.so is compiled with the same C compiler as the
version of NEURON the nrnivmodl on the PATH refers to.
57 changes: 36 additions & 21 deletions pype9/base/cells/code_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,32 +299,47 @@ def render_to_file(self, template, args, filename, directory, switches={},
with open(os.path.join(directory, filename), 'w') as f:
f.write(contents)

def path_to_exec(self, exec_name):
def path_to_utility(self, utility_name):
"""
Returns the full path to an executable by searching the "PATH"
environment variable
`exec_name` [str] -- Name of executable to search the execution path
return [str] -- Full path to executable
Parameters
----------
utility_name : str
Name of executable to search the execution path
Returns
-------
utility_path : str
Full path to executable
"""
if platform.system() == 'Windows':
exec_name += '.exe'
# Get the system path
system_path = os.environ['PATH'].split(os.pathsep)
# Append NEST_INSTALL_DIR/NRNHOME if present
system_path.extend(self.simulator_specific_paths())
# Check the system path for the command
exec_path = None
for dr in system_path:
path = join(dr, exec_name)
if os.path.exists(path):
exec_path = path
break
if not exec_path:
raise Pype9BuildError(
"Could not find executable '{}' on the system path '{}'"
.format(exec_name, ':'.join(system_path)))
return exec_path
# Check to see whether the path of the utility has been saved in the
# 'paths' directory (typically during installation)
saved_path_path = os.path.join(os.path.dirname(pype9.__file__),
'paths', utility_name + '_path')
try:
with open(saved_path_path) as f:
utility_path = f.read()
except OSError:
if platform.system() == 'Windows':
utility_name += '.exe'
# Get the system path
system_path = os.environ['PATH'].split(os.pathsep)
# Append NEST_INSTALL_DIR/NRNHOME if present
system_path.extend(self.simulator_specific_paths())
# Check the system path for the command
utility_path = None
for dr in system_path:
path = join(dr, utility_name)
if os.path.exists(path):
utility_path = path
break
if not utility_path:
raise Pype9BuildError(
"Could not find executable '{}' on the system path '{}'"
.format(utility_name, ':'.join(system_path)))
return utility_path

def simulator_specific_paths(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion pype9/nest/cells/code_gen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class CodeGenerator(BaseCodeGenerator):
def __init__(self, build_cores=1):
super(CodeGenerator, self).__init__()
self._build_cores = build_cores
nest_config = self.path_to_exec('nest-config')
nest_config = self.path_to_utility('nest-config')
compiler = sp.check_output('{} --compiler'.format(nest_config),
shell=True)
self._compiler = compiler[:-1] # strip trailing \n
Expand Down
6 changes: 3 additions & 3 deletions pype9/neuron/cells/code_gen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ class CodeGenerator(BaseCodeGenerator):

def __init__(self, gsl_path=None):
super(CodeGenerator, self).__init__()
self.nrnivmodl_path = self.path_to_exec('nrnivmodl')
self.modlunit_path = self.path_to_exec('modlunit')
self.nrnivmodl_path = self.path_to_utility('nrnivmodl')
self.modlunit_path = self.path_to_utility('modlunit')
self.nrnivmodl_flags = [
'-L' + self.LIBNINEMLNRN_PATH,
'-Wl,-rpath,' + self.LIBNINEMLNRN_PATH,
Expand All @@ -81,7 +81,7 @@ def __init__(self, gsl_path=None):
try:
# Check nest-config (if installed) to get any paths needed for
# gsl
nest_config_path = self.path_to_exec('nest-config')
nest_config_path = self.path_to_utility('nest-config')
nest_lflags = sp.Popen(
[nest_config_path, '--libs'],
stdout=sp.PIPE).communicate()[0].split()
Expand Down
52 changes: 31 additions & 21 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,49 +39,54 @@ class build(_build):

def run(self):
_build.run(self)
# Get directory of package to be installed
package_dir = os.path.join(os.getcwd(), self.build_lib, 'pype9')
# Save path to nrnivmodl and nest-config in hidden files for future
# reference while building generated code
# Get locations of utilities required for the build process (must be
# on the system PATH
self.nrnivmodl_path = self.path_to_exec('nrnivmodl')
neuron_code_gen_dir = os.path.join(package_dir, 'neuron', 'cells',
'code_gen')
with open(os.path.join(neuron_code_gen_dir,
'.nrnivmodlpath'), 'w') as f:
f.write(self.nrnivmodl_path)
self.nest_config_path = self.path_to_exec('nest-config')
nest_code_gen_dir = os.path.join(package_dir, 'nest', 'cells',
'code_gen')
with open(os.path.join(nest_code_gen_dir,
'.nestconfigpath'), 'w') as f:
f.write(self.nest_config_path)
# Complie libninemlnrn (for random distribution support in generated
# NEURON mechanisms)
# NMODL mechanisms)
print("Attempting to build libninemlnrn")
libninemlnrn_dir = os.path.join(neuron_code_gen_dir, 'libninemlnrn')
libninemlnrn_dir = os.path.join(
package_dir, 'neuron', 'cells', 'code_gen', 'libninemlnrn')
try:
cc = self.get_nrn_cc()
gsl_prefixes = self.get_gsl_prefixes()
echo_cmd = 'pwd; ls'
# Compile libninemlnrn
compile_cmd = '{} -fPIC -c -o nineml.o nineml.cpp {}'.format(
cc, ' '.join('-I{}/include'.format(p) for p in gsl_prefixes))
self.run_cmd(
compile_cmd, work_dir=libninemlnrn_dir,
fail_msg=("Unable to compile libninemlnrn extensions"))
# Link libninemlnrn
if platform.system() == 'Darwin':
# On macOS '-install_name' option needs to be set to allow
# rpath to find the compiled library
install_name = "-install_name @rpath/libninemlnrn.so "
else:
install_name = ""
link_cmd = (
"{} -shared {} {}"
"-lm -lgslcblas -lgsl -o libninemlnrn.so nineml.o -lc".format(
"{} -shared {} {} -lm -lgslcblas -lgsl "
"-o libninemlnrn.so nineml.o -lc".format(
cc, ' '.join('-L{}/lib'.format(p) for p in gsl_prefixes),
install_name))
for cmd in (echo_cmd, compile_cmd, link_cmd):
self.run_cmd(
cmd, work_dir=libninemlnrn_dir,
fail_msg=("Unable to compile libninemlnrn extensions"))
self.run_cmd(
link_cmd, work_dir=libninemlnrn_dir,
fail_msg=("Unable to link libninemlnrn extensions"))
print("Successfully compiled libninemlnrn extension.")
except CouldNotCompileNRNRandDistrException as e:
print("WARNING! Unable to compile libninemlnrn: "
"random distributions in NMODL files will not work:\n{}"
.format(e))
# Save paths to utilities to be referenced when building generated code
self.write_path('nest-config', self.nest_config_path)
self.write_path('nrnivmodl', self.nrnivmodl_path)
# Try to save the path of modlunit
try:
self.write_path('modlunit', self.path_to_exec('modlunit'))
except CouldNotCompileNRNRandDistrException:
pass # Not actually required but included in built for add. check

def run_cmd(self, cmd, work_dir, fail_msg):
p = sp.Popen(cmd, shell=True, stdin=sp.PIPE, stdout=sp.PIPE,
Expand Down Expand Up @@ -212,6 +217,11 @@ def path_to_exec(self, exec_name):
.format(exec_name, ':'.join(system_path)))
return exec_path

def write_path(self, name, path):
with open(os.path.join(self.package_dir, 'paths',
name + '_path'), 'w') as f:
f.write(path)


setup(
name="pype9",
Expand Down

0 comments on commit ac62e6e

Please sign in to comment.