1""" 2Test suite for _osx_support: shared OS X support functions. 3""" 4 5import os 6import platform 7import stat 8import sys 9import unittest 10 11from test.support import os_helper 12 13import _osx_support 14 15@unittest.skipUnless(sys.platform.startswith("darwin"), "requires OS X") 16class Test_OSXSupport(unittest.TestCase): 17 18 def setUp(self): 19 self.maxDiff = None 20 self.prog_name = 'bogus_program_xxxx' 21 self.temp_path_dir = os.path.abspath(os.getcwd()) 22 self.env = self.enterContext(os_helper.EnvironmentVarGuard()) 23 for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 24 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC', 25 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', 26 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'): 27 if cv in self.env: 28 self.env.unset(cv) 29 30 def add_expected_saved_initial_values(self, config_vars, expected_vars): 31 # Ensure that the initial values for all modified config vars 32 # are also saved with modified keys. 33 expected_vars.update(('_OSX_SUPPORT_INITIAL_'+ k, 34 config_vars[k]) for k in config_vars 35 if config_vars[k] != expected_vars[k]) 36 37 def test__find_executable(self): 38 if self.env['PATH']: 39 self.env['PATH'] = self.env['PATH'] + ':' 40 self.env['PATH'] = self.env['PATH'] + os.path.abspath(self.temp_path_dir) 41 os_helper.unlink(self.prog_name) 42 self.assertIsNone(_osx_support._find_executable(self.prog_name)) 43 self.addCleanup(os_helper.unlink, self.prog_name) 44 with open(self.prog_name, 'w') as f: 45 f.write("#!/bin/sh\n/bin/echo OK\n") 46 os.chmod(self.prog_name, stat.S_IRWXU) 47 self.assertEqual(self.prog_name, 48 _osx_support._find_executable(self.prog_name)) 49 50 def test__read_output(self): 51 if self.env['PATH']: 52 self.env['PATH'] = self.env['PATH'] + ':' 53 self.env['PATH'] = self.env['PATH'] + os.path.abspath(self.temp_path_dir) 54 os_helper.unlink(self.prog_name) 55 self.addCleanup(os_helper.unlink, self.prog_name) 56 with open(self.prog_name, 'w') as f: 57 f.write("#!/bin/sh\n/bin/echo ExpectedOutput\n") 58 os.chmod(self.prog_name, stat.S_IRWXU) 59 self.assertEqual('ExpectedOutput', 60 _osx_support._read_output(self.prog_name)) 61 62 def test__find_build_tool(self): 63 out = _osx_support._find_build_tool('cc') 64 self.assertTrue(os.path.isfile(out), 65 'cc not found - check xcode-select') 66 67 def test__get_system_version(self): 68 self.assertTrue(platform.mac_ver()[0].startswith( 69 _osx_support._get_system_version())) 70 71 def test__remove_original_values(self): 72 config_vars = { 73 'CC': 'gcc-test -pthreads', 74 } 75 expected_vars = { 76 'CC': 'clang -pthreads', 77 } 78 cv = 'CC' 79 newvalue = 'clang -pthreads' 80 _osx_support._save_modified_value(config_vars, cv, newvalue) 81 self.assertNotEqual(expected_vars, config_vars) 82 _osx_support._remove_original_values(config_vars) 83 self.assertEqual(expected_vars, config_vars) 84 85 def test__save_modified_value(self): 86 config_vars = { 87 'CC': 'gcc-test -pthreads', 88 } 89 expected_vars = { 90 'CC': 'clang -pthreads', 91 } 92 self.add_expected_saved_initial_values(config_vars, expected_vars) 93 cv = 'CC' 94 newvalue = 'clang -pthreads' 95 _osx_support._save_modified_value(config_vars, cv, newvalue) 96 self.assertEqual(expected_vars, config_vars) 97 98 def test__save_modified_value_unchanged(self): 99 config_vars = { 100 'CC': 'gcc-test -pthreads', 101 } 102 expected_vars = config_vars.copy() 103 cv = 'CC' 104 newvalue = 'gcc-test -pthreads' 105 _osx_support._save_modified_value(config_vars, cv, newvalue) 106 self.assertEqual(expected_vars, config_vars) 107 108 def test__supports_universal_builds(self): 109 import platform 110 mac_ver_tuple = tuple(int(i) for i in 111 platform.mac_ver()[0].split('.')[0:2]) 112 self.assertEqual(mac_ver_tuple >= (10, 4), 113 _osx_support._supports_universal_builds()) 114 115 def test__find_appropriate_compiler(self): 116 compilers = ( 117 ('gcc-test', 'i686-apple-darwin11-llvm-gcc-4.2'), 118 ('clang', 'clang version 3.1'), 119 ) 120 config_vars = { 121 'CC': 'gcc-test -pthreads', 122 'CXX': 'cc++-test', 123 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', 124 'LDFLAGS': '-arch ppc -arch i386 -g', 125 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 126 'BLDSHARED': 'gcc-test -bundle -arch ppc -arch i386 -g', 127 'LDSHARED': 'gcc-test -bundle -arch ppc -arch i386 ' 128 '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', 129 } 130 expected_vars = { 131 'CC': 'clang -pthreads', 132 'CXX': 'clang++', 133 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', 134 'LDFLAGS': '-arch ppc -arch i386 -g', 135 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 136 'BLDSHARED': 'clang -bundle -arch ppc -arch i386 -g', 137 'LDSHARED': 'clang -bundle -arch ppc -arch i386 ' 138 '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', 139 } 140 self.add_expected_saved_initial_values(config_vars, expected_vars) 141 142 suffix = (':' + self.env['PATH']) if self.env['PATH'] else '' 143 self.env['PATH'] = os.path.abspath(self.temp_path_dir) + suffix 144 for c_name, c_output in compilers: 145 os_helper.unlink(c_name) 146 self.addCleanup(os_helper.unlink, c_name) 147 with open(c_name, 'w') as f: 148 f.write("#!/bin/sh\n/bin/echo " + c_output) 149 os.chmod(c_name, stat.S_IRWXU) 150 self.assertEqual(expected_vars, 151 _osx_support._find_appropriate_compiler( 152 config_vars)) 153 154 def test__remove_universal_flags(self): 155 config_vars = { 156 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', 157 'LDFLAGS': '-arch ppc -arch i386 -g', 158 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 159 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 160 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 161 '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', 162 } 163 expected_vars = { 164 'CFLAGS': '-fno-strict-aliasing -g -O3 ', 165 'LDFLAGS': ' -g', 166 'CPPFLAGS': '-I. ', 167 'BLDSHARED': 'gcc-4.0 -bundle -g', 168 'LDSHARED': 'gcc-4.0 -bundle -g', 169 } 170 self.add_expected_saved_initial_values(config_vars, expected_vars) 171 172 self.assertEqual(expected_vars, 173 _osx_support._remove_universal_flags( 174 config_vars)) 175 176 def test__remove_universal_flags_alternate(self): 177 # bpo-38360: also test the alternate single-argument form of -isysroot 178 config_vars = { 179 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', 180 'LDFLAGS': '-arch ppc -arch i386 -g', 181 'CPPFLAGS': '-I. -isysroot/Developer/SDKs/MacOSX10.4u.sdk', 182 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 183 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 184 '-isysroot/Developer/SDKs/MacOSX10.4u.sdk -g', 185 } 186 expected_vars = { 187 'CFLAGS': '-fno-strict-aliasing -g -O3 ', 188 'LDFLAGS': ' -g', 189 'CPPFLAGS': '-I. ', 190 'BLDSHARED': 'gcc-4.0 -bundle -g', 191 'LDSHARED': 'gcc-4.0 -bundle -g', 192 } 193 self.add_expected_saved_initial_values(config_vars, expected_vars) 194 195 self.assertEqual(expected_vars, 196 _osx_support._remove_universal_flags( 197 config_vars)) 198 199 def test__remove_unsupported_archs(self): 200 config_vars = { 201 'CC': 'clang', 202 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', 203 'LDFLAGS': '-arch ppc -arch i386 -g', 204 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 205 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 206 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 207 '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', 208 } 209 expected_vars = { 210 'CC': 'clang', 211 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch i386 ', 212 'LDFLAGS': ' -arch i386 -g', 213 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 214 'BLDSHARED': 'gcc-4.0 -bundle -arch i386 -g', 215 'LDSHARED': 'gcc-4.0 -bundle -arch i386 ' 216 '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', 217 } 218 self.add_expected_saved_initial_values(config_vars, expected_vars) 219 220 suffix = (':' + self.env['PATH']) if self.env['PATH'] else '' 221 self.env['PATH'] = os.path.abspath(self.temp_path_dir) + suffix 222 c_name = 'clang' 223 os_helper.unlink(c_name) 224 self.addCleanup(os_helper.unlink, c_name) 225 # exit status 255 means no PPC support in this compiler chain 226 with open(c_name, 'w') as f: 227 f.write("#!/bin/sh\nexit 255") 228 os.chmod(c_name, stat.S_IRWXU) 229 self.assertEqual(expected_vars, 230 _osx_support._remove_unsupported_archs( 231 config_vars)) 232 233 def test__override_all_archs(self): 234 self.env['ARCHFLAGS'] = '-arch x86_64' 235 config_vars = { 236 'CC': 'clang', 237 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', 238 'LDFLAGS': '-arch ppc -arch i386 -g', 239 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 240 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 241 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 242 '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', 243 } 244 expected_vars = { 245 'CC': 'clang', 246 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch x86_64', 247 'LDFLAGS': ' -g -arch x86_64', 248 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', 249 'BLDSHARED': 'gcc-4.0 -bundle -g -arch x86_64', 250 'LDSHARED': 'gcc-4.0 -bundle -isysroot ' 251 '/Developer/SDKs/MacOSX10.4u.sdk -g -arch x86_64', 252 } 253 self.add_expected_saved_initial_values(config_vars, expected_vars) 254 255 self.assertEqual(expected_vars, 256 _osx_support._override_all_archs( 257 config_vars)) 258 259 def test__check_for_unavailable_sdk(self): 260 config_vars = { 261 'CC': 'clang', 262 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' 263 '-isysroot /Developer/SDKs/MacOSX10.1.sdk', 264 'LDFLAGS': '-arch ppc -arch i386 -g', 265 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.1.sdk', 266 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 267 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 268 '-isysroot /Developer/SDKs/MacOSX10.1.sdk -g', 269 } 270 expected_vars = { 271 'CC': 'clang', 272 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' 273 ' ', 274 'LDFLAGS': '-arch ppc -arch i386 -g', 275 'CPPFLAGS': '-I. ', 276 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 277 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 278 ' -g', 279 } 280 self.add_expected_saved_initial_values(config_vars, expected_vars) 281 282 self.assertEqual(expected_vars, 283 _osx_support._check_for_unavailable_sdk( 284 config_vars)) 285 286 def test__check_for_unavailable_sdk_alternate(self): 287 # bpo-38360: also test the alternate single-argument form of -isysroot 288 config_vars = { 289 'CC': 'clang', 290 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' 291 '-isysroot/Developer/SDKs/MacOSX10.1.sdk', 292 'LDFLAGS': '-arch ppc -arch i386 -g', 293 'CPPFLAGS': '-I. -isysroot/Developer/SDKs/MacOSX10.1.sdk', 294 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 295 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 296 '-isysroot/Developer/SDKs/MacOSX10.1.sdk -g', 297 } 298 expected_vars = { 299 'CC': 'clang', 300 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' 301 ' ', 302 'LDFLAGS': '-arch ppc -arch i386 -g', 303 'CPPFLAGS': '-I. ', 304 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', 305 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' 306 ' -g', 307 } 308 self.add_expected_saved_initial_values(config_vars, expected_vars) 309 310 self.assertEqual(expected_vars, 311 _osx_support._check_for_unavailable_sdk( 312 config_vars)) 313 314 def test_get_platform_osx(self): 315 # Note, get_platform_osx is currently tested more extensively 316 # indirectly by test_sysconfig and test_distutils 317 config_vars = { 318 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' 319 '-isysroot /Developer/SDKs/MacOSX10.1.sdk', 320 'MACOSX_DEPLOYMENT_TARGET': '10.6', 321 } 322 result = _osx_support.get_platform_osx(config_vars, ' ', ' ', ' ') 323 self.assertEqual(('macosx', '10.6', 'fat'), result) 324 325if __name__ == "__main__": 326 unittest.main() 327