| #!/usr/bin/env python |
| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
| import unittest |
| |
| SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| LIB_DIR = os.path.dirname(SCRIPT_DIR) |
| TOOLS_DIR = os.path.dirname(LIB_DIR) |
| SDK_DIR = os.path.dirname(TOOLS_DIR) |
| DATA_DIR = os.path.join(SCRIPT_DIR, 'data') |
| BUILD_TOOLS_DIR = os.path.join(SDK_DIR, 'build_tools') |
| |
| sys.path.append(LIB_DIR) |
| sys.path.append(TOOLS_DIR) |
| sys.path.append(BUILD_TOOLS_DIR) |
| |
| import build_paths |
| import get_shared_deps |
| import getos |
| |
| TOOLCHAIN_OUT = os.path.join(build_paths.OUT_DIR, 'sdk_tests', 'toolchain') |
| NACL_X86_GLIBC_TOOLCHAIN = os.path.join(TOOLCHAIN_OUT, |
| '%s_x86' % getos.GetPlatform(), |
| 'nacl_x86_glibc') |
| |
| |
| def StripDependencies(deps): |
| '''Strip the dirnames and version suffixes from |
| a list of nexe dependencies. |
| |
| e.g: |
| /path/to/libpthread.so.1a2d3fsa -> libpthread.so |
| ''' |
| names = [] |
| for name in deps: |
| name = os.path.basename(name) |
| if '.so.' in name: |
| name = name.rsplit('.', 1)[0] |
| names.append(name) |
| return names |
| |
| |
| class TestGetNeeded(unittest.TestCase): |
| def setUp(self): |
| self.tempdir = None |
| self.toolchain = NACL_X86_GLIBC_TOOLCHAIN |
| self.objdump = os.path.join(self.toolchain, 'bin', 'i686-nacl-objdump') |
| if os.name == 'nt': |
| self.objdump += '.exe' |
| self.Mktemp() |
| self.dyn_nexe = self.createTestNexe('test_dynamic_x86_32.nexe', 'i686') |
| self.dyn_deps = set(['libc.so', 'runnable-ld.so', |
| 'libgcc_s.so', 'libpthread.so']) |
| |
| def tearDown(self): |
| if self.tempdir: |
| shutil.rmtree(self.tempdir) |
| |
| def Mktemp(self): |
| self.tempdir = tempfile.mkdtemp() |
| |
| def createTestNexe(self, name, arch): |
| '''Create an empty test .nexe file for use in create_nmf tests. |
| |
| This is used rather than checking in test binaries since the |
| checked in binaries depend on .so files that only exist in the |
| certain SDK that built them. |
| ''' |
| compiler = os.path.join(self.toolchain, 'bin', '%s-nacl-g++' % arch) |
| if os.name == 'nt': |
| compiler += '.exe' |
| os.environ['CYGWIN'] = 'nodosfilewarning' |
| program = 'int main() { return 0; }' |
| name = os.path.join(self.tempdir, name) |
| cmd = [compiler, '-pthread', '-x' , 'c', '-o', name, '-'] |
| p = subprocess.Popen(cmd, stdin=subprocess.PIPE) |
| p.communicate(input=program) |
| self.assertEqual(p.returncode, 0) |
| return name |
| |
| def testStatic(self): |
| nexe = os.path.join(DATA_DIR, 'test_static_x86_32.nexe') |
| # GetNeeded should not raise an error if objdump is not set, but the .nexe |
| # is statically linked. |
| objdump = None |
| lib_path = [] |
| needed = get_shared_deps.GetNeeded([nexe], objdump, lib_path) |
| |
| # static nexe should have exactly one needed file |
| self.assertEqual(len(needed), 1) |
| self.assertEqual(needed.keys()[0], nexe) |
| |
| # arch of needed file should be x86-32 |
| arch = needed.values()[0] |
| self.assertEqual(arch, 'x86-32') |
| |
| def testDynamic(self): |
| libdir = os.path.join(self.toolchain, 'x86_64-nacl', 'lib32') |
| needed = get_shared_deps.GetNeeded([self.dyn_nexe], |
| lib_path=[libdir], |
| objdump=self.objdump) |
| names = needed.keys() |
| |
| # this nexe has 5 dependencies |
| expected = set(self.dyn_deps) |
| expected.add(os.path.basename(self.dyn_nexe)) |
| |
| basenames = set(StripDependencies(names)) |
| self.assertEqual(expected, basenames) |
| |
| def testMissingArchLibrary(self): |
| libdir = os.path.join(self.toolchain, 'x86_64-nacl', 'lib32') |
| lib_path = [libdir] |
| nexes = ['libgcc_s.so.1'] |
| # CreateNmfUtils uses the 32-bit library path, but not the 64-bit one |
| # so searching for a 32-bit library should succeed while searching for |
| # a 64-bit one should fail. |
| get_shared_deps.GleanFromObjdump(nexes, 'x86-32', self.objdump, lib_path) |
| self.assertRaises(get_shared_deps.Error, |
| get_shared_deps.GleanFromObjdump, |
| nexes, 'x86-64', self.objdump, lib_path) |
| |
| def testCorrectArch(self): |
| lib_path = [os.path.join(self.toolchain, 'x86_64-nacl', 'lib32'), |
| os.path.join(self.toolchain, 'x86_64-nacl', 'lib')] |
| |
| needed = get_shared_deps.GetNeeded([self.dyn_nexe], |
| lib_path=lib_path, |
| objdump=self.objdump) |
| for arch in needed.itervalues(): |
| self.assertEqual(arch, 'x86-32') |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |