1# ___________________________________________________________________________ 2# 3# Pyomo: Python Optimization Modeling Objects 4# Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC 5# Under the terms of Contract DE-NA0003525 with National Technology and 6# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain 7# rights in this software. 8# This software is distributed under the 3-clause BSD License. 9# ___________________________________________________________________________ 10 11import shutil 12import glob 13import os 14import sys 15import tempfile 16 17from pyomo.common.envvar import PYOMO_CONFIG_DIR 18from pyomo.common.fileutils import this_file_dir 19 20 21def handleReadonly(function, path, excinfo): 22 excvalue = excinfo[1] 23 if excvalue.errno == errno.EACCES: 24 os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777 25 function(path) 26 else: 27 raise 28 29 30def build_appsi(args=[]): 31 print('\n\n**** Building APPSI ****') 32 import setuptools 33 from distutils.dist import Distribution 34 from pybind11.setup_helpers import Pybind11Extension, build_ext 35 import pybind11.setup_helpers 36 37 appsi_root = this_file_dir() 38 sources = [ 39 os.path.join(appsi_root, 'cmodel', 'src', file_) 40 for file_ in ( 41 'expression.cpp', 42 'common.cpp', 43 'nl_writer.cpp', 44 'lp_writer.cpp', 45 'cmodel_bindings.cpp', 46 ) 47 ] 48 49 class appsi_build_ext(build_ext): 50 def run(self): 51 basedir = os.path.abspath(os.path.curdir) 52 if self.inplace: 53 tmpdir = os.path.join(this_file_dir(), 'cmodel') 54 else: 55 tmpdir = os.path.abspath(tempfile.mkdtemp()) 56 print("Building in '%s'" % tmpdir) 57 os.chdir(tmpdir) 58 try: 59 super(appsi_build_ext, self).run() 60 if not self.inplace: 61 library = glob.glob("build/*/appsi_cmodel.*")[0] 62 target = os.path.join( 63 PYOMO_CONFIG_DIR, 'lib', 64 'python%s.%s' % sys.version_info[:2], 65 'site-packages', '.') 66 if not os.path.exists(target): 67 os.makedirs(target) 68 shutil.copy(library, target) 69 finally: 70 os.chdir(basedir) 71 if not self.inplace: 72 shutil.rmtree(tmpdir, onerror=handleReadonly) 73 74 try: 75 original_pybind11_setup_helpers_macos = pybind11.setup_helpers.MACOS 76 pybind11.setup_helpers.MACOS = False 77 78 package_config = { 79 'name': 'appsi_cmodel', 80 'packages': [], 81 'ext_modules': [ 82 Pybind11Extension("appsi_cmodel", sources) 83 ], 84 'cmdclass': { 85 "build_ext": appsi_build_ext, 86 }, 87 } 88 89 dist = Distribution(package_config) 90 dist.script_args = ['build_ext'] + args 91 dist.parse_command_line() 92 dist.run_command('build_ext') 93 finally: 94 pybind11.setup_helpers.MACOS = original_pybind11_setup_helpers_macos 95 96 97class AppsiBuilder(object): 98 def __call__(self, parallel): 99 return build_appsi() 100 101 102if __name__ == '__main__': 103 # Note: this recognizes the "--inplace" command line argument: build 104 # directory will be put in the source tree (and preserved), and the 105 # SO will be left in appsi/cmodel. 106 build_appsi(sys.argv[1:]) 107