diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py index 783d4dca843..b76f0d41cf6 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -15,7 +15,7 @@ the "typical" Unix-style command-line C compiler: __revision__ = "$Id$" -import os, sys +import os, sys, re from types import StringType, NoneType from distutils import sysconfig @@ -305,10 +305,30 @@ class UnixCCompiler(CCompiler): dylib_f = self.library_filename(lib, lib_type='dylib') static_f = self.library_filename(lib, lib_type='static') + if sys.platform == 'darwin': + # On OSX users can specify an alternate SDK using + # '-isysroot', calculate the SDK root if it is specified + # (and use it further on) + cflags = sysconfig.get_config_var('CFLAGS') + m = re.search(r'-isysroot\s+(\S+)', cflags) + if m is None: + sysroot = '/' + else: + sysroot = m.group(1) + + + for dir in dirs: shared = os.path.join(dir, shared_f) dylib = os.path.join(dir, dylib_f) static = os.path.join(dir, static_f) + + if sys.platform == 'darwin' and ( + dir.startswith('/System/') or dir.startswith('/usr/')): + shared = os.path.join(sysroot, dir[1:], shared_f) + dylib = os.path.join(sysroot, dir[1:], dylib_f) + static = os.path.join(sysroot, dir[1:], static_f) + # We're second-guessing the linker here, with not much hard # data to go on: GCC seems to prefer the shared library, so I'm # assuming that *all* Unix C compilers do. And of course I'm diff --git a/setup.py b/setup.py index 7d6cadaf402..7294a1614c7 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,25 @@ def add_dir_to_list(dirlist, dir): if dir is not None and os.path.isdir(dir) and dir not in dirlist: dirlist.insert(0, dir) +def macosx_sdk_root(): + """ + Return the directory of the current OSX SDK, + or '/' if no SDK was specified. + """ + cflags = sysconfig.get_config_var('CFLAGS') + m = re.search(r'-isysroot\s+(\S+)', cflags) + if m is None: + sysroot = '/' + else: + sysroot = m.group(1) + return sysroot + +def is_macosx_sdk_path(path): + """ + Returns True if 'path' can be located in an OSX SDK + """ + return path.startswith('/usr/') or path.startswith('/System/') + def find_file(filename, std_dirs, paths): """Searches for the directory where a given file is located, and returns a possibly-empty list of additional directories, or None @@ -40,15 +59,28 @@ def find_file(filename, std_dirs, paths): 'paths' is a list of additional locations to check; if the file is found in one of them, the resulting list will contain the directory. """ + if sys.platform == 'darwin': + # Honor the MacOSX SDK setting when one was specified. + # An SDK is a directory with the same structure as a real + # system, but with only header files and libraries. + sysroot = macosx_sdk_root() # Check the standard locations for dir in std_dirs: f = os.path.join(dir, filename) + + if sys.platform == 'darwin' and is_macosx_sdk_path(dir): + f = os.path.join(sysroot, dir[1:], filename) + if os.path.exists(f): return [] # Check the additional directories for dir in paths: f = os.path.join(dir, filename) + + if sys.platform == 'darwin' and is_macosx_sdk_path(dir): + f = os.path.join(sysroot, dir[1:], filename) + if os.path.exists(f): return [dir] @@ -60,11 +92,19 @@ def find_library_file(compiler, libname, std_dirs, paths): if result is None: return None + if sys.platform == 'darwin': + sysroot = macosx_sdk_root() + # Check whether the found file is in one of the standard directories dirname = os.path.dirname(result) for p in std_dirs: # Ensure path doesn't end with path separator p = p.rstrip(os.sep) + + if sys.platform == 'darwin' and is_macosx_sdk_path(p): + if os.path.join(sysroot, p[1:]) == dirname: + return [ ] + if p == dirname: return [ ] @@ -73,6 +113,11 @@ def find_library_file(compiler, libname, std_dirs, paths): for p in paths: # Ensure path doesn't end with path separator p = p.rstrip(os.sep) + + if sys.platform == 'darwin' and is_macosx_sdk_path(p): + if os.path.join(sysroot, p[1:]) == dirname: + return [ p ] + if p == dirname: return [p] else: @@ -560,7 +605,7 @@ class PyBuildExt(build_ext): # library and then a static library, instead of first looking # for dynamic libraries on the entiry path. # This way a staticly linked custom readline gets picked up - # before the (broken) dynamic library in /usr/lib. + # before the (possibly broken) dynamic library in /usr/lib. readline_extra_link_args = ('-Wl,-search_paths_first',) else: readline_extra_link_args = () @@ -631,24 +676,24 @@ class PyBuildExt(build_ext): openssl_ver = 0 openssl_ver_re = re.compile( '^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+(0x[0-9a-fA-F]+)' ) - for ssl_inc_dir in inc_dirs + search_for_ssl_incs_in: - name = os.path.join(ssl_inc_dir, 'openssl', 'opensslv.h') - if os.path.isfile(name): - try: - incfile = open(name, 'r') - for line in incfile: - m = openssl_ver_re.match(line) - if m: - openssl_ver = eval(m.group(1)) - break - except IOError: - pass - # first version found is what we'll use (as the compiler should) - if openssl_ver: - break + # look for the openssl version header on the compiler search path. + opensslv_h = find_file('openssl/opensslv.h', [], + inc_dirs + search_for_ssl_incs_in) + if opensslv_h: + name = os.path.join(opensslv_h[0], 'openssl/opensslv.h') + if sys.platform == 'darwin' and is_macosx_sdk_path(name): + name = os.path.join(macosx_sdk_root(), name[1:]) + try: + incfile = open(name, 'r') + for line in incfile: + m = openssl_ver_re.match(line) + if m: + openssl_ver = eval(m.group(1)) + except IOError, msg: + print "IOError while reading opensshv.h:", msg + pass - #print 'openssl_ver = 0x%08x' % openssl_ver min_openssl_ver = 0x00907000 have_any_openssl = ssl_incs is not None and ssl_libs is not None have_usable_openssl = (have_any_openssl and @@ -781,12 +826,19 @@ class PyBuildExt(build_ext): db_ver_inc_map = {} + if sys.platform == 'darwin': + sysroot = macosx_sdk_root() + class db_found(Exception): pass try: # See whether there is a Sleepycat header in the standard # search path. for d in inc_dirs + db_inc_paths: f = os.path.join(d, "db.h") + + if sys.platform == 'darwin' and is_macosx_sdk_path(d): + f = os.path.join(sysroot, d[1:], "db.h") + if db_setup_debug: print "db: looking for db.h in", f if os.path.exists(f): f = open(f).read() @@ -833,7 +885,20 @@ class PyBuildExt(build_ext): db_incdir.replace("include", 'lib64'), db_incdir.replace("include", 'lib'), ] - db_dirs_to_check = filter(os.path.isdir, db_dirs_to_check) + + if sys.platform != 'darwin': + db_dirs_to_check = filter(os.path.isdir, db_dirs_to_check) + + else: + # Same as other branch, but takes OSX SDK into account + tmp = [] + for dn in db_dirs_to_check: + if is_macosx_sdk_path(dn): + if os.path.isdir(os.path.join(sysroot, dn[1:])): + tmp.append(dn) + else: + if os.path.isdir(dn): + tmp.append(dn) # Look for a version specific db-X.Y before an ambiguoius dbX # XXX should we -ever- look for a dbX name? Do any @@ -895,8 +960,15 @@ class PyBuildExt(build_ext): # Scan the default include directories before the SQLite specific # ones. This allows one to override the copy of sqlite on OSX, # where /usr/include contains an old version of sqlite. + if sys.platform == 'darwin': + sysroot = macosx_sdk_root() + for d in inc_dirs + sqlite_inc_paths: f = os.path.join(d, "sqlite3.h") + + if sys.platform == 'darwin' and is_macosx_sdk_path(d): + f = os.path.join(sysroot, d[1:], "sqlite3.h") + if os.path.exists(f): if sqlite_setup_debug: print "sqlite: found %s"%f incf = open(f).read() @@ -984,6 +1056,12 @@ class PyBuildExt(build_ext): # the more recent berkeleydb's db.h file first in the include path # when attempting to compile and it will fail. f = "/usr/include/db.h" + + if sys.platform == 'darwin': + if is_macosx_sdk_path(f): + sysroot = macosx_sdk_root() + f = os.path.join(sysroot, f[1:]) + if os.path.exists(f) and not db_incs: data = open(f).read() m = re.search(r"#s*define\s+HASHVERSION\s+2\s*", data) @@ -1490,14 +1568,22 @@ class PyBuildExt(build_ext): join(os.getenv('HOME'), '/Library/Frameworks') ] + sysroot = macosx_sdk_root() + # Find the directory that contains the Tcl.framework and Tk.framework # bundles. # XXX distutils should support -F! for F in framework_dirs: # both Tcl.framework and Tk.framework should be present + + for fw in 'Tcl', 'Tk': - if not exists(join(F, fw + '.framework')): - break + if is_macosx_sdk_path(F): + if not exists(join(sysroot, F[1:], fw + '.framework')): + break + else: + if not exists(join(F, fw + '.framework')): + break else: # ok, F is now directory with both frameworks. Continure # building @@ -1527,7 +1613,12 @@ class PyBuildExt(build_ext): # architectures. cflags = sysconfig.get_config_vars('CFLAGS')[0] archs = re.findall('-arch\s+(\w+)', cflags) - fp = os.popen("file %s/Tk.framework/Tk | grep 'for architecture'"%(F,)) + + if is_macosx_sdk_path(F): + fp = os.popen("file %s/Tk.framework/Tk | grep 'for architecture'"%(os.path.join(sysroot, F[1:]),)) + else: + fp = os.popen("file %s/Tk.framework/Tk | grep 'for architecture'"%(F,)) + detected_archs = [] for ln in fp: a = ln.split()[-1]