diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake index 49ffbabe79e5a33ec1d103577d0daaae77b31c1d..7b593f23adb91ac5e09bf628accf516fcef7c553 100644 --- a/cmake_support/OST.cmake +++ b/cmake_support/OST.cmake @@ -505,9 +505,9 @@ macro(pymod) return() endif() if (_ARG_OUTPUT_DIR) - set(PYMOD_DIR "openstructure/${_ARG_OUTPUT_DIR}") + set(PYMOD_DIR "python${PYTHON_VERSION}/site-packages/${_ARG_OUTPUT_DIR}") else() - set(PYMOD_DIR "openstructure/${_ARG_PREFIX}/${_ARG_NAME}") + set(PYMOD_DIR "python${PYTHON_VERSION}/site-packages/${_ARG_PREFIX}/${_ARG_NAME}") endif() set(_LIB_NAME ${_ARG_PREFIX}_${_ARG_NAME}) set(PYMOD_STAGE_DIR "${LIB_STAGE_PATH}/${PYMOD_DIR}") diff --git a/deployment/macos/deps.py b/deployment/macos/deps.py index 2693db881eac8a5c648019ae79d56c46846aa43a..91ef55c9ada53c569dcf76fde350f57f8161f9e6 100644 --- a/deployment/macos/deps.py +++ b/deployment/macos/deps.py @@ -27,7 +27,7 @@ def _deps_for_lib(lib, pool, recursive=True): return def collect_deps(stage_dir, components, binaries, libexec_binaries, - site_packages, site_packages_dir): + site_packages, site_packages_dir, libexec_path='openstructure'): """ Collect the dependencies for the given components and returns a list of frameworks/libraries that the component depends on. @@ -239,7 +239,8 @@ def make_standalone(stage_dir, outdir, no_includes, force_no_rpath=False, # when running in non-gui mode, we are most likely missing the boost # python library. Let's add it to the list of dependencies by # inspecting "_ost_base.so". - _deps_for_lib(os.path.join(stage_dir, 'lib/openstructure/ost/_ost_base.so'), + pymod_dir='lib/python%d.%d/site-packages' % sys.version_info[0:2] + _deps_for_lib(os.path.join(stage_dir, pymod_dir, 'ost/_ost_base.so'), deps, recursive=False) print 'copying dependencies' copy_deps(deps, outdir) @@ -249,8 +250,8 @@ def make_standalone(stage_dir, outdir, no_includes, force_no_rpath=False, print 'copying binaries' copy_binaries(stage_dir, outdir, binaries, scripts, 'bin') print 'copying pymod' - shutil.copytree(os.path.join(stage_dir, 'lib/openstructure'), - os.path.join(outdir, 'lib/openstructure')) + shutil.copytree(os.path.join(stage_dir,pymod_dir), + os.path.join(outdir, pymod_dir)) copied_py_framework=False non_std_python=False if os.path.exists(os.path.join(outdir, 'lib/Python.framework')): @@ -310,9 +311,9 @@ def make_standalone(stage_dir, outdir, no_includes, force_no_rpath=False, for sp in SITE_PACKAGES: src=get_python_module_path(sp) if os.path.isdir(src): - shutil.copytree(src, os.path.join(outdir, 'lib/openstructure', sp)) + shutil.copytree(src, os.path.join(outdir, pymod_dir, sp)) else: - shutil.copy(src, os.path.join(outdir, 'lib/openstructure', sp)) + shutil.copy(src, os.path.join(outdir, pymod_dir, sp)) print 'updating link commands of python shared objects' os.path.walk(os.path.join(outdir, 'lib'), update_pymod_shared_objects, diff --git a/deployment/macos/pack.py b/deployment/macos/pack.py new file mode 100644 index 0000000000000000000000000000000000000000..d849446be5d0f2e01d2ff27bed4c958cf5e7d16d --- /dev/null +++ b/deployment/macos/pack.py @@ -0,0 +1,357 @@ +""" +deploy.py helps you package your code into a standalone application. + +for now, MacOS X and Linux are supported... +""" +import os +import subprocess +import shutil +import sys +import glob + +def _lib_name(component): + return 'lib%s.dylib' % component + +def _deps_for_lib(lib, pool, recursive=True): + if lib in pool: + return + otool=subprocess.Popen(['otool', '-L', lib], stdout=subprocess.PIPE) + output=otool.communicate()[0] + lines=output.split('\n')[1:] + for line in lines: + d=line.split(' ')[0].strip() + if len(d)>0: + if d==lib: + continue + if d not in pool: + if d.startswith('/System') or d.startswith('/usr/lib'): + continue + if recursive: + _deps_for_lib(d, pool) + pool.add(d) + return + +def collect_deps(stage_dir, components, binaries, libexec_binaries, + site_packages, site_packages_dir, libexec_path='openstructure'): + """ + Collect the dependencies for the given components and returns a list of + frameworks/libraries that the component depends on. + """ + pool=set() + for component in components: + lib_name=os.path.abspath(os.path.join(stage_dir, 'lib', + _lib_name(component))) + if not os.path.exists(lib_name): + print 'WARNING:', lib_name, 'does not exist' + if lib_name not in pool: + _deps_for_lib(lib_name, pool) + pool.add(lib_name) + for bin in binaries: + bin_name=os.path.abspath(os.path.join(stage_dir, 'bin', + bin)) + if not os.path.exists(bin_name): + print 'WARNING:', bin_name, 'does not exist' + continue + if bin_name not in pool: + _deps_for_lib(bin_name, pool) + for bin in libexec_binaries: + bin_name=os.path.abspath(os.path.join(stage_dir, 'libexec', libexec_path, + bin)) + if not os.path.exists(bin_name): + print 'WARNING:', bin_name, 'does not exist' + continue + if bin_name not in pool: + _deps_for_lib(bin_name, pool) + for site_package in site_packages: + full_path=get_python_module_path(site_package) + print full_path + if not os.path.exists(full_path): + print 'WARNING:', site_package, 'does not exists' + continue + if os.path.isdir(full_path): + for so_file in glob.glob(os.path.join(full_path, '*.so')): + _deps_for_lib(so_file, pool) + return pool + +LIBEXEC_SCRIPTS=['ost_config'] +LIBEXEC_BINARIES=[] +GUI_LIBEXEC_BINARIES=['gosty'] +BINARIES=['ldt', 'chemdict_tool', 'tmalign', 'tmscore'] +GUI_BINARIES=[] +GUI_COMPONENTS=['gfx', 'gui', 'info'] +COMPONENTS=['mol', 'geom', 'conop', 'seq_alg', 'seq', + 'img', 'img_alg', 'io', 'db', 'base'] +GUI_SCRIPTS=['dng'] +SCRIPTS=['ost'] +CHANGE_ID_RPATH='install_name_tool -id @rpath/%s %s' +CHANGE_ID='install_name_tool -id @rpath/%s %s' +CHANGE_LOAD_CMD_RPATH='install_name_tool -change %s @rpath/%s %s' +CHANGE_LOAD_CMD='install_name_tool -change %s @executable_path/%s %s' +ADD_RPATH='install_name_tool -add_rpath %s %s 2> /dev/null' +SITE_PACKAGES=[] +GUI_SITE_PACKAGES=['sip.so', 'sipconfig.py', 'sipdistutils.py', 'PyQt4'] +REMOVE_HEADERS='rm -rf `find %s/lib -type d -name Headers`' +REMOVE_CURRENT='rm -rf `find %s/lib -type d -name Current`' +# collect libs of non-standard libraries/frameworks we depend on + +def copy_binaries(stage_dir, outdir, binary_names, scripts, bin_dir, + append_bin=True): + + exe_path=os.path.abspath(os.path.join(outdir, bin_dir)) + for binary_name in binary_names: + if append_bin: + bin_name=os.path.join(stage_dir, bin_dir, binary_name) + else: + bin_name=os.path.join(stage_dir, binary_name) + if not os.path.exists(bin_name): + print 'WARNING:', binary_name, 'does not exist' + continue + dst_name=os.path.join(outdir, bin_dir, os.path.basename(bin_name)) + shutil.copy(bin_name, dst_name) + update_load_commands(dst_name, True, exe_path) + for script in scripts: + shutil.copy(os.path.join(stage_dir, bin_dir, script), + os.path.join(outdir,bin_dir, script)) + +def split_framework_components(abs_path): + """ + Splits the path pointing to a dynamic library within a framework + + '/System/Frameworks/A.framework/Versions/4/A' => + ['/System/Frameworks/A.framework', 'Versions/4/A'] + """ + parts=abs_path.split('/') + for i, s in enumerate(parts): + if s.endswith('.framework'): + lead=os.path.join('/', *parts[:i+1]) + trail=os.path.join(*parts[i+1:]) + return lead, trail + +def change_id(id, lib): + os.chmod(lib, 0666) + os.system(CHANGE_ID_RPATH % (id,lib)) + os.chmod(lib, 0444) + +def update_load_commands(lib, exe, exe_path): + direct_deps=set() + _deps_for_lib(lib, direct_deps, recursive=False) + os.chmod(lib, 0666) + for direct_dep in direct_deps: + if direct_dep.endswith('.dylib'): + new_name=os.path.basename(direct_dep) + os.system(CHANGE_LOAD_CMD_RPATH % (direct_dep, new_name, lib)) + else: + assert direct_dep.find('.framework/')>=0 + framework_path, rel_path=split_framework_components(direct_dep) + framework_name=os.path.basename(framework_path) + new_name=os.path.join(framework_name, rel_path) + os.system(CHANGE_LOAD_CMD_RPATH % (direct_dep, new_name, lib)) + if exe: + os.chmod(lib, 0555) + else: + os.chmod(lib, 0444) + +def copy_deps(dependencies, outdir): + exe_path=os.path.join(outdir, 'bin') + for dep in dependencies: + if dep.endswith('.dylib'): + dst_name=os.path.join(outdir, 'lib', os.path.basename(dep)) + if not os.path.exists(dep): + continue + if os.path.exists(dst_name): + continue + shutil.copy(dep, dst_name) + change_id(os.path.basename(dep), dst_name) + update_load_commands(dst_name, False, exe_path) + else: + assert dep.find('.framework/')>=0 + framework_path, rel_path=split_framework_components(dep) + framework_name=os.path.basename(framework_path) + dst_name=os.path.join(outdir, 'lib', framework_name) + shutil.copytree(framework_path, dst_name) + change_id(os.path.join(dst_name, rel_path), + os.path.join(dst_name, rel_path)) + os.unlink(os.path.join(dst_name, os.path.splitext(framework_name)[0])) + update_load_commands(os.path.join(dst_name, rel_path), False, + exe_path) + +def update_pymod_shared_objects(lib_path, path, files): + exe_path=os.path.abspath(os.path.join(lib_path, '../bin')) + for f in files: + if not os.path.exists(os.path.join(path, f)): + continue + base, ext=os.path.splitext(f) + if ext=='.so': + path_to_lib_path=os.path.relpath(lib_path, path) + abs_name=os.path.join(path, f) + os.system(ADD_RPATH % (path_to_lib_path, abs_name)) + update_load_commands(abs_name, False, exe_path) + elif ext in ('.pyc', '.pyo'): + os.unlink(os.path.join(path, f)) + +def merge_tree(src, dst): + """ + Similar to shutil.copytree, but does not complain when the destination + directory already exists. + """ + names = os.listdir(src) + if not os.path.exists(dst): + os.makedirs(dst) + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + merge_tree(srcname, dstname) + else: + shutil.copy2(srcname, dstname) + except (IOError, os.error), why: + errors.append((srcname, dstname, str(why))) + except shutil.Error, err: + errors.extend(err.args[0]) + try: + shutil.copystat(src, dst) + except OSError, why: + if WindowsError is not None and isinstance(why, WindowsError): + # Copying file access times may fail on Windows + pass + else: + errors.extend((src, dst, str(why))) + if errors: + raise shutil.Error, errors + +def get_site_package_dir(): + """ + Get site-package directory of this python installation. This assumes + that ost was linked against the same version of Python (which is a very + reasonable thing to do, as this script is most likely run with ost). + """ + for p in sys.path: + pattern='/site-packages' + index=p.find(pattern) + if index>=0: + return p[:index+len(pattern)] + raise RuntimeError("Couldn't determine site-packages location") + +def get_python_module_path(module): + for path in sys.path: + full_path=os.path.join(path, module) + if os.path.exists(full_path): + return full_path + return None + + +def get_python_home(): + """ + Derive Python home by looking at the location of the os module + """ + return os.path.dirname(sys.modules['os'].__file__) + + +class Package(object): + def __init__(self, name, root_dir, binaries=[], scripts=[], + modules=[], libraries=[], libexec_dir=None, libexec_scripts=[]): + self.root_dir=root_dir + self.name=name + self.binaries=binaries + self.scripts=scripts + self.libraries=libraries + self.libexec_dir=libexec_dir + self.libexec_scripts=libexec_scripts + self.pymod_dir=os.path.join('lib', 'python%d.%d' % sys.version_info[0:2], + 'site-packages') + self.modules=modules + self.libexec_binaries=[] + self.site_packages=[] + self.site_packages_dir='' + def status(self, message): + print '%s: %s' % (self.name, message) + + def _prepare_output_dir(self, output_dir): + """ + Prepares the output directory structure, including lib, bin and an optional + libexec directory. + """ + #if os.path.exists(output_dir): + # shutil.rmtree(output_dir) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + if not os.path.exists(os.path.join(output_dir, 'bin')): + os.makedirs(os.path.join(output_dir, 'bin')) + if not os.path.exists(os.path.join(output_dir, 'lib')): + os.makedirs(os.path.join(output_dir, 'lib')) + if self.libexec_dir: + out_exec_dir=os.path.join(output_dir, 'libexec', self.libexec_dir) + if not os.path.exists(out_exec_dir): + print 'making...', out_exec_dir + os.makedirs(out_exec_dir) + def _copy_site_packages(self, output_dir): + for sp in SITE_PACKAGES: + src=get_python_module_path(sp) + if os.path.isdir(src): + merge_tree(src, os.path.joini(output_dir, self.pymod_dir, sp)) + else: + shutil.copy(src, os.path.join(output_dir, self.pymod_dir, sp)) + print 'updating link commands of python shared objects' + os.path.walk(os.path.join(output_dir, 'lib'), + update_pymod_shared_objects, + os.path.join(output_dir, 'lib')) + + def ship(self, output_dir): + self._prepare_output_dir(output_dir) + if os.path.exists(os.path.join(self.root_dir, 'share')): + self.status('copying shared data files') + merge_tree(os.path.join(self.root_dir, 'share'), + os.path.join(output_dir, 'share')) + self.status('collecting dependencies') + deps=collect_deps(self.root_dir, self.libraries, self.binaries, + self.libexec_binaries, self.site_packages, + self.site_packages_dir) + # when running in non-gui mode, we are most likely missing the boost + # python library. Let's add it to the list of dependencies by + # inspecting "_ost_base.so". + pymod_dir='lib/python%d.%d/site-packages' % sys.version_info[0:2] + _deps_for_lib(os.path.join(self.root_dir, pymod_dir, 'ost/_ost_base.so'), + deps, recursive=False) + self.status('copying dependencies') + copy_deps(deps, output_dir) + if self.libexec_dir: + self.status('copying libexec binaries') + copy_binaries(self.root_dir, output_dir, self.libexec_binaries, + self.libexec_scripts, + os.path.join('libexec', self.libexec_dir)) + self.status('copying binaries') + copy_binaries(self.root_dir, output_dir, self.binaries, + self.scripts, 'bin') + self.status('copying pymod') + merge_tree(os.path.join(self.root_dir,self.pymod_dir), + os.path.join(output_dir, self.pymod_dir)) + self._copy_site_packages(output_dir) + +class OpenStructure(Package): + def __init__(self, stage_dir, minimal=True): + libs=['ost_mol', 'ost_geom', 'ost_conop', 'ost_seq_alg', + 'ost_io', 'ost_db', 'ost_base', 'ost_seq', 'ost_mol_alg'] + super(OpenStructure, self).__init__('OpenStructure', stage_dir, + binaries=['ldt', 'chemdict_tool'], + libexec_scripts=['ost_config'], + scripts=['ost'], + libraries=libs, + libexec_dir='openstructure') + +class Qmean(Package): + def __init__(self, stage_dir): + super(Qmean, self).__init__('Qmean', stage_dir, + scripts=['qmean'], + libexec_scripts=['qmean_script.py'], + libexec_dir='qmean', + libraries=['qmean']) +ost=OpenStructure('../../stage') +qmean=Qmean('../../../../../qmean/stage') +ost.ship('qmean') +qmean.ship('qmean') + diff --git a/doc/conf/conf.py b/doc/conf/conf.py index b2d284a53bf8f2843ea9a25b8b0828af9ccc2865..e87782b4c33be7d3f95160d365b9f600743470ad 100644 --- a/doc/conf/conf.py +++ b/doc/conf/conf.py @@ -13,13 +13,12 @@ import sys, os -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. +site_packs='python%d.%d/site-packages' % sys.version_info[0:2] sys.path.append(os.path.join(os.path.abspath('../..'), - 'stage/lib/openstructure')) + 'stage/lib', site_packs)) sys.path.append(os.path.join(os.path.abspath('../..'), - 'stage/lib64/openstructure')) + 'stage/lib64', site_packs)) +print site_packs import ost # -- General configuration ----------------------------------------------------- diff --git a/modules/gui/src/gosty.cc b/modules/gui/src/gosty.cc index 49750b9dca33c65e927d52dad461d5973b96fc80..670c454c1886f0c1c2013954d3996a38060781b6 100644 --- a/modules/gui/src/gosty.cc +++ b/modules/gui/src/gosty.cc @@ -108,13 +108,20 @@ String get_ost_root() void setup_python_search_path(const String& root, PythonInterpreter& pi) { + std::stringstream site_pkgs; + site_pkgs << "python" << PY_MAJOR_VERSION << "." << PY_MINOR_VERSION; #ifdef _MSC_VER - pi.AppendModulePath(QString::fromStdString(root+"\\lib\\openstructure")); + pi.AppendModulePath(QString::fromStdString(root+"\\lib\\"+site_pkgs.str() + +"\\site-packages")); #else # if (defined(__ppc64__) || defined(__x86_64__)) && !defined(__APPLE__) - pi.AppendModulePath(QString::fromStdString(root+"/lib64/openstructure")); + pi.AppendModulePath(QString::fromStdString(root+"/lib64/"+ + site_pkgs.str()+ + "site-packages")); # else - pi.AppendModulePath(QString::fromStdString(root+"/lib/openstructure")); + pi.AppendModulePath(QString::fromStdString(root+"/lib/"+ + site_pkgs.str()+ + "/site-packages")); # endif #endif pi.AppendModulePath("."); diff --git a/modules/mol/alg/src/lddt.cc b/modules/mol/alg/src/lddt.cc index 2142989048973aaec76da73470c078e69e212c16..fdd70d953c802f7319611071b57ca1e30a2b5c32 100644 --- a/modules/mol/alg/src/lddt.cc +++ b/modules/mol/alg/src/lddt.cc @@ -283,6 +283,7 @@ int main (int argc, char **argv) EntityView v=model.CreateFullView(); boost::filesystem::path pathstring(files[i]); + #if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 String filestring=pathstring.string(); #else diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 652d98238ce990ca81cdb9b99338a9a7fa0721d3..bdf0e613a983a19ea0944669ac704cc43e922e46 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -33,13 +33,13 @@ if (NOT ENABLE_STATIC) set(INIT_SCRIPTS init_cl.py ) - + set(SPD "${LIB_DIR}/python${PYTHON_VERSION}/site-packages") if (ENABLE_GUI) list(APPEND INIT_SCRIPTS init.py) endif() copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}" "${STAGE_DIR}/${LIB_DIR}/openstructure" "${INIT_SCRIPTS}" "python init scripts" ost_scripts) - install(FILES ${INIT_SCRIPTS} DESTINATION "${LIB_DIR}/openstructure") + install(FILES ${INIT_SCRIPTS} DESTINATION "${SPD}") endif() diff --git a/scripts/init_cl.py b/scripts/init_cl.py index 09b38ed9785b1075acbdc5dbfe8de8e1d14d21f3..d4a14df4cd339872dc62c2de5898b04f07e75c76 100644 --- a/scripts/init_cl.py +++ b/scripts/init_cl.py @@ -26,10 +26,11 @@ parser.add_option("-v", "--verbosity_level", action="store", type="int", dest="v parser.disable_interspersed_args() (options, args) = parser.parse_args() +_site_packs='python%d.%d/site-packages' % sys.version_info[0:2] if platform.machine()=='x86_64': - sys.path.insert(0, os.getenv('DNG_ROOT')+'/lib64/openstructure') + sys.path.insert(0, os.path.join(os.getenv('DNG_ROOT'), 'lib64', _site_packs)) else: - sys.path.insert(0,os.getenv('DNG_ROOT')+'/lib/openstructure') + sys.path.insert(0,os.path.join(os.getenv('DNG_ROOT'), 'lib', _site_packs)) from ost import * import ost diff --git a/scripts/ost.in b/scripts/ost.in index 90c74f045e5ceff238b207c3043046d96546c57f..407daed10f8d2b6fed92f1724c9c4b369bef0244 100755 --- a/scripts/ost.in +++ b/scripts/ost.in @@ -31,6 +31,6 @@ BIN_DIR=`dirname "$SCRIPT_NAME"` source $BIN_DIR/../@LIBEXEC_PATH@/ost_config -$pyexec $interactive "$DNG_ROOT/@LIBDIR@/openstructure/init_cl.py" $opts +$pyexec $interactive "$DNG_ROOT/@LIBDIR@/python@PYTHON_VERSION@/site-packages/init_cl.py" $opts RC=$? exit $RC diff --git a/scripts/ost_config.in b/scripts/ost_config.in index faaae8e264e655496fe35471dc0bb685c6a6f59b..5894bdb12c62241d556e04fb909eb9f83a17c5ef 100644 --- a/scripts/ost_config.in +++ b/scripts/ost_config.in @@ -24,7 +24,7 @@ export DNG_ROOT=`cd "$BIN_DIR/..";pwd` export DNG_BINDIR="$DNG_ROOT/bin" export DNG_LIBDIR="$DNG_ROOT/@LIBDIR@" -export DNG_INITDIR="$DNG_LIBDIR/openstructure" +export DNG_INITDIR="$DNG_LIBDIR/python@PYTHON_VERSION@/site-packages" export PATH="$DNG_BINDIR:${PATH}" export DYLD_FRAMEWORK_PATH="$DNG_LIBDIR:${DYLD_FRAMEWORK_PATH}"