Remove remaining layering violations from test runner
[chromium-blink-merge.git] / ios / build / packaging / link_dependencies.py
blobdf541a63758a734f7fce000adb9a8ad7e4058369
1 #!/usr/bin/env python
3 # Copyright 2014 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 """Links the deps of a binary into a static library.
9 Run with a working directory, the name of a binary target, and the name of the
10 static library that should be produced. For example:
12 $ link_dependencies.py out/Release-iphoneos \
13 crnet_consumer.app/crnet_consumer \
14 out/Release-iphoneos/crnet_standalone.a
15 """
17 import argparse
18 import os
19 import subprocess
22 class SubprocessError(Exception):
23 pass
26 def extract_inputs(query_result, prefix=''):
27 """Extracts inputs from ninja query output.
29 Given 'ninja -t query' output for a target, extracts all the inputs of that
30 target, prefixing them with an optional prefix. Inputs prefixed with '|' are
31 implicit, so we discard them as they shouldn't be linked into the resulting
32 binary (these are things like the .ninja files themselves, dep lists, and so
33 on).
35 Example query result:
36 arch/crnet_consumer.armv7:
37 input: link
38 obj/[long path...]/crnet_consumer.crnet_consumer_app_delegate.armv7.o
39 obj/[long path...]/crnet_consumer.crnet_consumer_view_controller.armv7.o
40 obj/[long path...]/crnet_consumer.main.armv7.o
41 libcrnet.a
42 libdata_reduction_proxy_code_browser.a
43 ... many more inputs ...
44 liburl_util.a
45 | obj/content/content.actions_depends.stamp
46 | gen/components/data_reduction_proxy/common/version.h
47 | obj/ui/resources/ui_resources.actions_rules_copies.stamp
48 ... more implicit inputs ...
49 outputs:
50 crnet_consumer.app/crnet_consumer
52 Args:
53 query_result: output from 'ninja -t query'
54 prefix: optional file system path to prefix to returned inputs
56 Returns:
57 A list of the inputs.
58 """
59 extracting = False
60 inputs = []
61 for line in query_result.splitlines():
62 if line.startswith(' input:'):
63 extracting = True
64 elif line.startswith(' outputs:'):
65 extracting = False
66 elif extracting and '|' not in line:
67 inputs.append(os.path.join(prefix, line.strip()))
68 return inputs
71 def query_ninja(target, workdir, prefix=''):
72 """Returns the inputs for the named target.
74 Queries ninja for the set of inputs of the named target, then returns the list
75 of inputs to that target.
77 Args:
78 target: ninja target name to query for
79 workdir: workdir for ninja
80 prefix: optional file system path to prefix to returned inputs
82 Returns:
83 A list of file system paths to the inputs to the named target.
84 """
85 proc = subprocess.Popen(['ninja', '-C', workdir, '-t', 'query', target],
86 stdout=subprocess.PIPE)
87 stdout, _ = proc.communicate()
88 return extract_inputs(stdout, prefix)
91 def is_library(target):
92 """Returns whether target is a library file."""
93 return os.path.splitext(target)[1] in ('.a', '.o')
96 def library_deps(targets, workdir, query=query_ninja):
97 """Returns the set of library dependencies for the supplied targets.
99 The entries in the targets list can be either a static library, an object
100 file, or an executable. Static libraries and object files are incorporated
101 directly; executables are treated as being thin executable inputs to a fat
102 executable link step, and have their own library dependencies added in their
103 place.
105 Args:
106 targets: list of targets to include library dependencies from
107 workdir: working directory to run ninja queries in
108 query: function taking target, workdir, and prefix and returning an input
110 Returns:
111 Set of library dependencies.
113 deps = set()
114 for target in targets:
115 if is_library(target):
116 deps.add(os.path.join(workdir, target))
117 else:
118 deps = deps.union(query(target, workdir, workdir))
119 return deps
122 def link(output, inputs):
123 """Links output from inputs using libtool.
125 Args:
126 output: file system path to desired output library
127 inputs: list of file system paths to input libraries
129 p = subprocess.Popen(['libtool', '-o', output] + inputs)
130 p.communicate()
131 if p.returncode != 0:
132 message = "subprocess libtool returned {0}".format(p.returncode)
133 raise SubprocessError(message)
136 def main():
137 parser = argparse.ArgumentParser(
138 description='Link dependencies of a ninja target into a static library')
139 parser.add_argument('workdir', nargs=1, help='ninja working directory')
140 parser.add_argument('target', nargs=1, help='target to query for deps')
141 parser.add_argument('output', nargs=1, help='path to output static library')
142 args = parser.parse_args()
144 inputs = query_ninja(args.target[0], args.workdir[0])
145 link(args.output[0], list(library_deps(inputs, args.workdir[0])))
148 if __name__ == '__main__':
149 main()