blob: d6ae5a494fe555d54385979a544743633918f532 [file] [log] [blame]
# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittest-only utility functions library."""
from __future__ import print_function
import os
from chromite.lib import cros_build_lib
from chromite.lib import osutils
class BuildELFError(Exception):
"""Generic error building an ELF file."""
def BuildELF(filename, defined_symbols=None, undefined_symbols=None,
used_libs=None, executable=False, static=False):
"""Builds a dynamic ELF with the provided import and exports.
Compiles and links a dynamic program that exports some functions, as libraries
do, and requires some symbols from other libraries. Dependencies shoud live
in the same directory as the result. This function
Args:
filename: The output filename where the ELF is created.
defined_symbols: The list of symbols this ELF exports.
undefined_symbols: The list of symbols this ELF requires from other ELFs.
used_libs: The list of libraries this ELF loads dynamically, including only
the name of the library. For example, 'bz2' rather than 'libbz2.so.1.0'.
executable: Whether the file has a main() function.
static: Whether the file is statically linked (implies executable=True).
"""
if defined_symbols is None:
defined_symbols = []
if undefined_symbols is None:
undefined_symbols = []
if used_libs is None:
used_libs = []
if static and not executable:
raise ValueError('static requires executable to be True.')
source = ''.join('void %s();\n' % sym for sym in undefined_symbols)
source += """
void __defined_symbols(const char*) __attribute__ ((visibility ("hidden")));
void __defined_symbols(const char* sym) {
%s
}
""" % ('\n '.join('%s();' % sym for sym in undefined_symbols))
source += ''.join("""
void %s() __attribute__ ((visibility ("default")));
void %s() { __defined_symbols("%s"); }
""" % (sym, sym, sym) for sym in defined_symbols)
if executable:
source += """
int main() {
__defined_symbols("main");
return 42;
}
"""
source_fn = filename + '_tmp.c'
osutils.WriteFile(source_fn, source)
outdir = os.path.dirname(filename)
cmd = ['gcc', '-o', filename, source_fn]
if not executable:
cmd += ['-shared', '-fPIC']
if static:
cmd += ['-static']
cmd += ['-L.', '-Wl,-rpath=./']
cmd += ['-l%s' % lib for lib in used_libs]
try:
cros_build_lib.RunCommand(
cmd, cwd=outdir, redirect_stdout=True, redirect_stderr=True,
print_cmd=False)
except cros_build_lib.RunCommandError, e:
raise BuildELFError('%s\n%s' % (e.message, e.result.error))
finally:
os.unlink(source_fn)