blob: 45ee526288284b7107e182a87afe3a6980441737 [file] [log] [blame]
#!/usr/bin/env python3
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version
# 2.0 (the "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
# Check for programs linked with libraries they don't in fact use.
# For example, if a program was linked with -lfoo but doesn't use any
# symbols from libfoo.
#
# The list of programs is gathered by scraping Automake files, which are
# themselves gathered from Autoconf. ldd does the actual business of
# checking for unused dependencies.
#
# There are a couple of manual exceptions listed below, either because
# we deliberately link with an unused library -- possibly for
# convenience -- or because I haven't figured out how to fix it yet.
#
# For now, this only checks the programs that we install,
# but it could potentially check our libraries as well.
import os.path
import re
import subprocess
import sys
config_files_re = re.compile(r'(?<=config_files=").*(?=")')
programs_re = re.compile(r'([^\n ]*_)PROGRAMS \+?= (.*)')
def get_dependencies(program):
args = [
'./libtool', '--mode=execute', 'ldd', '--unused', '--function-relocs',
program
]
for dependency in subprocess.Popen(args, stdout=subprocess.PIPE).stdout:
dependency = dependency.decode('utf-8')[:-1]
if any(
map(
os.path.basename(dependency).startswith,
[
'libdl.so.', # Because we add -ldl to LIBS
'libgcc_s.so.',
'libm.so.', # Why does Libtool call ld with -lm?
'libpthread.so.' # Because we add -lpthread to LIBS
])):
continue
# Why does Libtool call ld with -lcrypto -lresolv -lssl?
if os.path.basename(program) == 'traffic_manager':
if any(
map(
os.path.basename(dependency).startswith, [
'libcrypto.so.',
'libresolv.so.',
'libssl.so.'
])):
continue
if re.sub('\s+', '', dependency):
yield dependency
success = True
filename = 'config.status'
contents = open(filename).read()
config_files = config_files_re.search(contents).group(0)
for filename in config_files.split():
filename = filename + '.am'
if os.path.exists(filename):
contents = open(filename).read()
contents = contents.replace('\\\n', '')
for prefix, programs in programs_re.findall(contents):
if prefix not in [
'EXTRA_',
'check_',
'noinst_'
]:
for program in programs.split():
program = os.path.join(os.path.dirname(filename), program)
if os.path.exists(program):
dependencies = list(get_dependencies(program))
if len(dependencies) > 1:
success = False
print(program)
for dependency in dependencies:
print(dependency)
if not success:
sys.exit(1)