Adds trunk/talk folder of revision 359 from libjingles google code to
trunk/talk git-svn-id: http://webrtc.googlecode.com/svn/trunk@4318 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
313
talk/site_scons/site_tools/talk_linux.py
Normal file
313
talk/site_scons/site_tools/talk_linux.py
Normal file
@@ -0,0 +1,313 @@
|
||||
# Copyright 2010 Google Inc.
|
||||
# All Rights Reserved.
|
||||
# Author: tschmelcher@google.com (Tristan Schmelcher)
|
||||
|
||||
"""Tool for helpers used in linux building process."""
|
||||
|
||||
import os
|
||||
import SCons.Defaults
|
||||
import subprocess
|
||||
|
||||
|
||||
def _OutputFromShellCommand(command):
|
||||
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
|
||||
return process.communicate()[0].strip()
|
||||
|
||||
|
||||
# This is a pure SCons helper function.
|
||||
def _InternalBuildDebianPackage(env, debian_files, package_files,
|
||||
output_dir=None, force_version=None):
|
||||
"""Creates build rules to build a Debian package from the specified sources.
|
||||
|
||||
Args:
|
||||
env: SCons Environment.
|
||||
debian_files: Array of the Debian control file sources that should be
|
||||
copied into the package source tree, e.g., changelog, control, rules,
|
||||
etc.
|
||||
package_files: An array of 2-tuples listing the files that should be
|
||||
copied into the package source tree.
|
||||
The first element is the path where the file should be placed for the
|
||||
.install control file to find it, relative to the generated debian
|
||||
package source directory.
|
||||
The second element is the file source.
|
||||
output_dir: An optional directory to place the files in. If omitted, the
|
||||
current output directory is used.
|
||||
force_version: Optional. Forces the version of the package to start with
|
||||
this version string if specified. If the last entry in the changelog
|
||||
is not for a version that starts with this then a dummy entry is
|
||||
generated with this version and a ~prerelease suffix (so that the
|
||||
final version will compare as greater).
|
||||
|
||||
Return:
|
||||
A list of the targets (if any).
|
||||
"""
|
||||
if 0 != subprocess.call(['which', 'dpkg-buildpackage']):
|
||||
print ('dpkg-buildpackage not installed on this system; '
|
||||
'skipping DEB build stage')
|
||||
return []
|
||||
# Read the control file and changelog file to determine the package name,
|
||||
# version, and arch that the Debian build tools will use to name the
|
||||
# generated files.
|
||||
control_file = None
|
||||
changelog_file = None
|
||||
for file in debian_files:
|
||||
if os.path.basename(file) == 'control':
|
||||
control_file = env.File(file).srcnode().abspath
|
||||
elif os.path.basename(file) == 'changelog':
|
||||
changelog_file = env.File(file).srcnode().abspath
|
||||
if not control_file:
|
||||
raise Exception('Need to have a control file')
|
||||
if not changelog_file:
|
||||
raise Exception('Need to have a changelog file')
|
||||
source = _OutputFromShellCommand(
|
||||
"awk '/^Source:/ { print $2; }' " + control_file)
|
||||
packages = _OutputFromShellCommand(
|
||||
"awk '/^Package:/ { print $2; }' " + control_file).split('\n')
|
||||
version = _OutputFromShellCommand(
|
||||
"sed -nr '1 { s/.*\\((.*)\\).*/\\1/; p }' " + changelog_file)
|
||||
arch = _OutputFromShellCommand('dpkg --print-architecture')
|
||||
add_dummy_changelog_entry = False
|
||||
if force_version and not version.startswith(force_version):
|
||||
print ('Warning: no entry in ' + changelog_file + ' for version ' +
|
||||
force_version + ' (last is ' + version +'). A dummy entry will be ' +
|
||||
'generated. Remember to add the real changelog entry before ' +
|
||||
'releasing.')
|
||||
version = force_version + '~prerelease'
|
||||
add_dummy_changelog_entry = True
|
||||
source_dir_name = source + '_' + version + '_' + arch
|
||||
target_file_names = [ source_dir_name + '.changes' ]
|
||||
for package in packages:
|
||||
package_file_name = package + '_' + version + '_' + arch + '.deb'
|
||||
target_file_names.append(package_file_name)
|
||||
# The targets
|
||||
if output_dir:
|
||||
targets = [os.path.join(output_dir, s) for s in target_file_names]
|
||||
else:
|
||||
targets = target_file_names
|
||||
# Path to where we will construct the debian build tree.
|
||||
deb_build_tree = os.path.join(source_dir_name, 'deb_build_tree')
|
||||
# First copy the files.
|
||||
for file in package_files:
|
||||
env.Command(os.path.join(deb_build_tree, file[0]), file[1],
|
||||
SCons.Defaults.Copy('$TARGET', '$SOURCE'))
|
||||
env.Depends(targets, os.path.join(deb_build_tree, file[0]))
|
||||
# Now copy the Debian metadata sources. We have to do this all at once so
|
||||
# that we can remove the target directory before copying, because there
|
||||
# can't be any other stale files there or else dpkg-buildpackage may use
|
||||
# them and give incorrect build output.
|
||||
copied_debian_files_paths = []
|
||||
for file in debian_files:
|
||||
copied_debian_files_paths.append(os.path.join(deb_build_tree, 'debian',
|
||||
os.path.basename(file)))
|
||||
copy_commands = [
|
||||
"""dir=$$(dirname $TARGET) && \
|
||||
rm -Rf $$dir && \
|
||||
mkdir -p $$dir && \
|
||||
cp $SOURCES $$dir && \
|
||||
chmod -R u+w $$dir"""
|
||||
]
|
||||
if add_dummy_changelog_entry:
|
||||
copy_commands += [
|
||||
"""debchange -c $$(dirname $TARGET)/changelog --newversion %s \
|
||||
--distribution UNRELEASED \
|
||||
'Developer preview build. (This entry was auto-generated.)'""" %
|
||||
version
|
||||
]
|
||||
env.Command(copied_debian_files_paths, debian_files, copy_commands)
|
||||
env.Depends(targets, copied_debian_files_paths)
|
||||
# Must explicitly specify -a because otherwise cross-builds won't work.
|
||||
# Must explicitly specify -D because -a disables it.
|
||||
# Must explicitly specify fakeroot because old dpkg tools don't assume that.
|
||||
env.Command(targets, None,
|
||||
"""dir=%(dir)s && \
|
||||
cd $$dir && \
|
||||
dpkg-buildpackage -b -uc -a%(arch)s -D -rfakeroot && \
|
||||
cd $$OLDPWD && \
|
||||
for file in %(targets)s; do \
|
||||
mv $$dir/../$$file $$(dirname $TARGET) || exit 1; \
|
||||
done""" %
|
||||
{'dir':env.Dir(deb_build_tree).path,
|
||||
'arch':arch,
|
||||
'targets':' '.join(target_file_names)})
|
||||
return targets
|
||||
|
||||
|
||||
def BuildDebianPackage(env, debian_files, package_files, force_version=None):
|
||||
"""Creates build rules to build a Debian package from the specified sources.
|
||||
|
||||
This is a Hammer-ified version of _InternalBuildDebianPackage that knows to
|
||||
put the packages in the Hammer staging dir.
|
||||
|
||||
Args:
|
||||
env: SCons Environment.
|
||||
debian_files: Array of the Debian control file sources that should be
|
||||
copied into the package source tree, e.g., changelog, control, rules,
|
||||
etc.
|
||||
package_files: An array of 2-tuples listing the files that should be
|
||||
copied into the package source tree.
|
||||
The first element is the path where the file should be placed for the
|
||||
.install control file to find it, relative to the generated debian
|
||||
package source directory.
|
||||
The second element is the file source.
|
||||
force_version: Optional. Forces the version of the package to start with
|
||||
this version string if specified. If the last entry in the changelog
|
||||
is not for a version that starts with this then a dummy entry is
|
||||
generated with this version and a ~prerelease suffix (so that the
|
||||
final version will compare as greater).
|
||||
|
||||
Return:
|
||||
A list of the targets (if any).
|
||||
"""
|
||||
if not env.Bit('host_linux'):
|
||||
return []
|
||||
return _InternalBuildDebianPackage(env, debian_files, package_files,
|
||||
output_dir='$STAGING_DIR', force_version=force_version)
|
||||
|
||||
|
||||
def _GetPkgConfigCommand():
|
||||
"""Return the pkg-config command line to use.
|
||||
|
||||
Returns:
|
||||
A string specifying the pkg-config command line to use.
|
||||
"""
|
||||
return os.environ.get('PKG_CONFIG') or 'pkg-config'
|
||||
|
||||
|
||||
def _EscapePosixShellArgument(arg):
|
||||
"""Escapes a shell command line argument so that it is interpreted literally.
|
||||
|
||||
Args:
|
||||
arg: The shell argument to escape.
|
||||
|
||||
Returns:
|
||||
The escaped string.
|
||||
"""
|
||||
return "'%s'" % arg.replace("'", "'\\''")
|
||||
|
||||
|
||||
def _HavePackage(package):
|
||||
"""Whether the given pkg-config package name is present on the build system.
|
||||
|
||||
Args:
|
||||
package: The name of the package.
|
||||
|
||||
Returns:
|
||||
True if the package is present, else False
|
||||
"""
|
||||
return subprocess.call('%s --exists %s' % (
|
||||
_GetPkgConfigCommand(),
|
||||
_EscapePosixShellArgument(package)), shell=True) == 0
|
||||
|
||||
|
||||
def _GetPackageFlags(flag_type, packages):
|
||||
"""Get the flags needed to compile/link against the given package(s).
|
||||
|
||||
Returns the flags that are needed to compile/link against the given pkg-config
|
||||
package(s).
|
||||
|
||||
Args:
|
||||
flag_type: The option to pkg-config specifying the type of flags to get.
|
||||
packages: The list of package names as strings.
|
||||
|
||||
Returns:
|
||||
The flags of the requested type.
|
||||
|
||||
Raises:
|
||||
subprocess.CalledProcessError: The pkg-config command failed.
|
||||
"""
|
||||
pkg_config = _GetPkgConfigCommand()
|
||||
command = ' '.join([pkg_config] +
|
||||
[_EscapePosixShellArgument(arg) for arg in
|
||||
[flag_type] + packages])
|
||||
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
|
||||
output = process.communicate()[0]
|
||||
if process.returncode != 0:
|
||||
raise subprocess.CalledProcessError(process.returncode, pkg_config)
|
||||
return output.strip().split(' ')
|
||||
|
||||
|
||||
def GetPackageParams(env, packages):
|
||||
"""Get the params needed to compile/link against the given package(s).
|
||||
|
||||
Returns the params that are needed to compile/link against the given
|
||||
pkg-config package(s).
|
||||
|
||||
Args:
|
||||
env: The current SCons environment.
|
||||
packages: The name of the package, or a list of names.
|
||||
|
||||
Returns:
|
||||
A dictionary containing the params.
|
||||
|
||||
Raises:
|
||||
Exception: One or more of the packages is not installed.
|
||||
"""
|
||||
if not env.Bit('host_linux'):
|
||||
return {}
|
||||
if not SCons.Util.is_List(packages):
|
||||
packages = [packages]
|
||||
for package in packages:
|
||||
if not _HavePackage(package):
|
||||
raise Exception(('Required package \"%s\" was not found. Please install '
|
||||
'the package that provides the \"%s.pc\" file.') %
|
||||
(package, package))
|
||||
package_ccflags = _GetPackageFlags('--cflags', packages)
|
||||
package_libs = _GetPackageFlags('--libs', packages)
|
||||
# Split package_libs into libs, libdirs, and misc. linker flags. (In a perfect
|
||||
# world we could just leave libdirs in link_flags, but some linkers are
|
||||
# somehow confused by the different argument order.)
|
||||
libs = [flag[2:] for flag in package_libs if flag[0:2] == '-l']
|
||||
libdirs = [flag[2:] for flag in package_libs if flag[0:2] == '-L']
|
||||
link_flags = [flag for flag in package_libs if flag[0:2] not in ['-l', '-L']]
|
||||
return {
|
||||
'ccflags': package_ccflags,
|
||||
'libs': libs,
|
||||
'libdirs': libdirs,
|
||||
'link_flags': link_flags,
|
||||
'dependent_target_settings' : {
|
||||
'libs': libs[:],
|
||||
'libdirs': libdirs[:],
|
||||
'link_flags': link_flags[:],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def EnableFeatureWherePackagePresent(env, bit, cpp_flag, package):
|
||||
"""Enable a feature if a required pkg-config package is present.
|
||||
|
||||
Args:
|
||||
env: The current SCons environment.
|
||||
bit: The name of the Bit to enable when the package is present.
|
||||
cpp_flag: The CPP flag to enable when the package is present.
|
||||
package: The name of the package.
|
||||
"""
|
||||
if not env.Bit('host_linux'):
|
||||
return
|
||||
if _HavePackage(package):
|
||||
env.SetBits(bit)
|
||||
env.Append(CPPDEFINES=[cpp_flag])
|
||||
else:
|
||||
print ('Warning: Package \"%s\" not found. Feature \"%s\" will not be '
|
||||
'built. To build with this feature, install the package that '
|
||||
'provides the \"%s.pc\" file.') % (package, bit, package)
|
||||
|
||||
def GetGccVersion(env):
|
||||
if env.Bit('cross_compile'):
|
||||
gcc_command = env['CXX']
|
||||
else:
|
||||
gcc_command = 'gcc'
|
||||
version_string = _OutputFromShellCommand(
|
||||
'%s --version | head -n 1 |'
|
||||
r'sed "s/.*\([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/g"' % gcc_command)
|
||||
return tuple([int(x or '0') for x in version_string.split('.')])
|
||||
|
||||
def generate(env):
|
||||
if env.Bit('linux'):
|
||||
env.AddMethod(EnableFeatureWherePackagePresent)
|
||||
env.AddMethod(GetPackageParams)
|
||||
env.AddMethod(BuildDebianPackage)
|
||||
env.AddMethod(GetGccVersion)
|
||||
|
||||
|
||||
def exists(env):
|
||||
return 1 # Required by scons
|
Reference in New Issue
Block a user