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