1 #!/usr/bin/env python 2 # Copyright 2014 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import os 7 import shutil 8 import subprocess 9 import sys 10 import tempfile 11 import unittest 12 13 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 14 LIB_DIR = os.path.dirname(SCRIPT_DIR) 15 TOOLS_DIR = os.path.dirname(LIB_DIR) 16 SDK_DIR = os.path.dirname(TOOLS_DIR) 17 DATA_DIR = os.path.join(SCRIPT_DIR, 'data') 18 BUILD_TOOLS_DIR = os.path.join(SDK_DIR, 'build_tools') 19 20 sys.path.append(LIB_DIR) 21 sys.path.append(TOOLS_DIR) 22 sys.path.append(BUILD_TOOLS_DIR) 23 24 import build_paths 25 import get_shared_deps 26 import getos 27 28 TOOLCHAIN_OUT = os.path.join(build_paths.OUT_DIR, 'sdk_tests', 'toolchain') 29 NACL_X86_GLIBC_TOOLCHAIN = os.path.join(TOOLCHAIN_OUT, 30 '%s_x86' % getos.GetPlatform(), 31 'nacl_x86_glibc') 32 33 34 def StripDependencies(deps): 35 '''Strip the dirnames and version suffixes from 36 a list of nexe dependencies. 37 38 e.g: 39 /path/to/libpthread.so.1a2d3fsa -> libpthread.so 40 ''' 41 names = [] 42 for name in deps: 43 name = os.path.basename(name) 44 if '.so.' in name: 45 name = name.rsplit('.', 1)[0] 46 names.append(name) 47 return names 48 49 50 class TestGetNeeded(unittest.TestCase): 51 def setUp(self): 52 self.tempdir = None 53 self.toolchain = NACL_X86_GLIBC_TOOLCHAIN 54 self.objdump = os.path.join(self.toolchain, 'bin', 'i686-nacl-objdump') 55 if os.name == 'nt': 56 self.objdump += '.exe' 57 self.Mktemp() 58 self.dyn_nexe = self.createTestNexe('test_dynamic_x86_32.nexe', 'i686') 59 self.dyn_deps = set(['libc.so', 'runnable-ld.so', 60 'libgcc_s.so', 'libpthread.so']) 61 62 def tearDown(self): 63 if self.tempdir: 64 shutil.rmtree(self.tempdir) 65 66 def Mktemp(self): 67 self.tempdir = tempfile.mkdtemp() 68 69 def createTestNexe(self, name, arch): 70 '''Create an empty test .nexe file for use in create_nmf tests. 71 72 This is used rather than checking in test binaries since the 73 checked in binaries depend on .so files that only exist in the 74 certain SDK that built them. 75 ''' 76 compiler = os.path.join(self.toolchain, 'bin', '%s-nacl-g++' % arch) 77 if os.name == 'nt': 78 compiler += '.exe' 79 os.environ['CYGWIN'] = 'nodosfilewarning' 80 program = 'int main() { return 0; }' 81 name = os.path.join(self.tempdir, name) 82 cmd = [compiler, '-pthread', '-x' , 'c', '-o', name, '-'] 83 p = subprocess.Popen(cmd, stdin=subprocess.PIPE) 84 p.communicate(input=program) 85 self.assertEqual(p.returncode, 0) 86 return name 87 88 def testStatic(self): 89 nexe = os.path.join(DATA_DIR, 'test_static_x86_32.nexe') 90 # GetNeeded should not raise an error if objdump is not set, but the .nexe 91 # is statically linked. 92 objdump = None 93 lib_path = [] 94 needed = get_shared_deps.GetNeeded([nexe], objdump, lib_path) 95 96 # static nexe should have exactly one needed file 97 self.assertEqual(len(needed), 1) 98 self.assertEqual(needed.keys()[0], nexe) 99 100 # arch of needed file should be x86-32 101 arch = needed.values()[0] 102 self.assertEqual(arch, 'x86-32') 103 104 def testDynamic(self): 105 libdir = os.path.join(self.toolchain, 'x86_64-nacl', 'lib32') 106 needed = get_shared_deps.GetNeeded([self.dyn_nexe], 107 lib_path=[libdir], 108 objdump=self.objdump) 109 names = needed.keys() 110 111 # this nexe has 5 dependencies 112 expected = set(self.dyn_deps) 113 expected.add(os.path.basename(self.dyn_nexe)) 114 115 basenames = set(StripDependencies(names)) 116 self.assertEqual(expected, basenames) 117 118 def testMissingArchLibrary(self): 119 libdir = os.path.join(self.toolchain, 'x86_64-nacl', 'lib32') 120 lib_path = [libdir] 121 nexes = ['libgcc_s.so.1'] 122 # CreateNmfUtils uses the 32-bit library path, but not the 64-bit one 123 # so searching for a 32-bit library should succeed while searching for 124 # a 64-bit one should fail. 125 get_shared_deps.GleanFromObjdump(nexes, 'x86-32', self.objdump, lib_path) 126 self.assertRaises(get_shared_deps.Error, 127 get_shared_deps.GleanFromObjdump, 128 nexes, 'x86-64', self.objdump, lib_path) 129 130 def testCorrectArch(self): 131 lib_path = [os.path.join(self.toolchain, 'x86_64-nacl', 'lib32'), 132 os.path.join(self.toolchain, 'x86_64-nacl', 'lib')] 133 134 needed = get_shared_deps.GetNeeded([self.dyn_nexe], 135 lib_path=lib_path, 136 objdump=self.objdump) 137 for arch in needed.itervalues(): 138 self.assertEqual(arch, 'x86-32') 139 140 141 if __name__ == '__main__': 142 unittest.main() 143