Skip to content

Commit ac86584

Browse files
committed
Unify common routines in build_api.py
Introduce prepare_toolchain() which handles: * deduplication of src_paths * config initialization * toolchain initialization * toolchain flags * returns toolchain Introduce scan_resources() which handles: * scanning of sources * scanning of include dirs * inclusion of addition include dirs * returns resources
1 parent 8ab89c1 commit ac86584

File tree

2 files changed

+127
-158
lines changed

2 files changed

+127
-158
lines changed

tools/build_api.py

Lines changed: 124 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -77,28 +77,13 @@ def add_result_to_report(report, result):
7777
result_wrap = { 0: result }
7878
report[target][toolchain][id_name].append(result_wrap)
7979

80-
def get_config(src_path, target, toolchain_name):
81-
# Convert src_path to a list if needed
82-
src_paths = [src_path] if type(src_path) != ListType else src_path
83-
# We need to remove all paths which are repeated to avoid
84-
# multiple compilations and linking with the same objects
85-
src_paths = [src_paths[0]] + list(set(src_paths[1:]))
80+
def get_config(src_paths, target, toolchain_name):
81+
# Convert src_paths to a list if needed
82+
if type(src_paths) != ListType:
83+
src_paths = [src_paths]
8684

87-
# Create configuration object
88-
config = Config(target, src_paths)
89-
90-
# If the 'target' argument is a string, convert it to a target instance
91-
if isinstance(target, basestring):
92-
try:
93-
target = TARGET_MAP[target]
94-
except KeyError:
95-
raise KeyError("Target '%s' not found" % target)
96-
97-
# Toolchain instance
98-
try:
99-
toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options=None, notify=None, macros=None, silent=True, extra_verbose=False)
100-
except KeyError as e:
101-
raise KeyError("Toolchain %s not supported" % toolchain_name)
85+
# Pass all params to the unified prepare_resources()
86+
toolchain = prepare_toolchain(src_paths, target, toolchain_name)
10287

10388
# Scan src_path for config files
10489
resources = toolchain.scan_resources(src_paths[0])
@@ -109,10 +94,10 @@ def get_config(src_path, target, toolchain_name):
10994
prev_features = set()
11095
while True:
11196
# Update the configuration with any .json files found while scanning
112-
config.add_config_files(resources.json_files)
97+
toolchain.config.add_config_files(resources.json_files)
11398

11499
# Add features while we find new ones
115-
features = config.get_features()
100+
features = toolchain.config.get_features()
116101
if features == prev_features:
117102
break
118103

@@ -121,29 +106,27 @@ def get_config(src_path, target, toolchain_name):
121106
resources += resources.features[feature]
122107

123108
prev_features = features
124-
config.validate_config()
109+
toolchain.config.validate_config()
125110

126-
cfg, macros = config.get_config_data()
127-
features = config.get_features()
111+
cfg, macros = toolchain.config.get_config_data()
112+
features = toolchain.config.get_features()
128113
return cfg, macros, features
129114

130-
def build_project(src_path, build_path, target, toolchain_name,
131-
libraries_paths=None, options=None, linker_script=None,
132-
clean=False, notify=None, verbose=False, name=None, macros=None, inc_dirs=None,
133-
jobs=1, silent=False, report=None, properties=None, project_id=None, project_description=None,
134-
extra_verbose=False, config=None):
135-
""" This function builds project. Project can be for example one test / UT
115+
def prepare_toolchain(src_paths, target, toolchain_name,
116+
macros=None, options=None, clean=False, jobs=1,
117+
notify=None, silent=False, verbose=False, extra_verbose=False, config=None):
118+
""" Prepares resource related objects - toolchain, target, config
119+
src_paths: the paths to source directories
120+
target: ['LPC1768', 'LPC11U24', 'LPC2368']
121+
toolchain_name: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR']
122+
clean: Rebuild everything if True
123+
notify: Notify function for logs
124+
verbose: Write the actual tools command lines if True
136125
"""
137126

138-
# Convert src_path to a list if needed
139-
src_paths = [src_path] if type(src_path) != ListType else src_path
140-
141127
# We need to remove all paths which are repeated to avoid
142128
# multiple compilations and linking with the same objects
143129
src_paths = [src_paths[0]] + list(set(src_paths[1:]))
144-
first_src_path = src_paths[0] if src_paths[0] != "." and src_paths[0] != "./" else getcwd()
145-
abs_path = abspath(first_src_path)
146-
project_name = basename(normpath(abs_path))
147130

148131
# If the configuration object was not yet created, create it now
149132
config = config or Config(target, src_paths)
@@ -161,65 +144,98 @@ def build_project(src_path, build_path, target, toolchain_name,
161144
except KeyError as e:
162145
raise KeyError("Toolchain %s not supported" % toolchain_name)
163146

164-
toolchain.VERBOSE = verbose
147+
toolchain.config = config
165148
toolchain.jobs = jobs
166149
toolchain.build_all = clean
150+
toolchain.VERBOSE = verbose
167151

168-
if name is None:
169-
# We will use default project name based on project folder name
170-
name = project_name
171-
toolchain.info("Building project %s (%s, %s)" % (project_name, target.name, toolchain_name))
172-
else:
173-
# User used custom global project name to have the same name for the
174-
toolchain.info("Building project %s to %s (%s, %s)" % (project_name, name, target.name, toolchain_name))
152+
return toolchain
175153

154+
def scan_resources(src_paths, toolchain, dependencies_paths=None, inc_dirs=None):
155+
""" Scan resources using initialized toolcain
156+
src_paths: the paths to source directories
157+
toolchain: valid toolchain object
158+
dependencies_paths: dependency paths that we should scan for include dirs
159+
inc_dirs: additional include directories which should be added to thescanner resources
160+
"""
161+
162+
# Scan src_path
163+
resources = toolchain.scan_resources(src_paths[0])
164+
for path in src_paths[1:]:
165+
resources.add(toolchain.scan_resources(path))
166+
167+
# Scan dependency paths for include dirs
168+
if dependencies_paths is not None:
169+
for path in dependencies_paths:
170+
lib_resources = toolchain.scan_resources(path)
171+
resources.inc_dirs.extend(lib_resources.inc_dirs)
176172

173+
# Add additional include directories if passed
174+
if inc_dirs:
175+
if type(inc_dirs) == ListType:
176+
resources.inc_dirs.extend(inc_dirs)
177+
else:
178+
resources.inc_dirs.append(inc_dirs)
179+
180+
# Load resources into the config system which might expand/modify resources based on config data
181+
resources = toolchain.config.load_resources(resources)
182+
183+
# Set the toolchain's configuration data
184+
toolchain.set_config_data(toolchain.config.get_config_data())
185+
186+
return resources
187+
188+
def build_project(src_paths, build_path, target, toolchain_name,
189+
libraries_paths=None, options=None, linker_script=None,
190+
clean=False, notify=None, verbose=False, name=None, macros=None, inc_dirs=None,
191+
jobs=1, silent=False, report=None, properties=None, project_id=None, project_description=None,
192+
extra_verbose=False, config=None):
193+
""" This function builds project. Project can be for example one test / UT
194+
"""
195+
196+
# Convert src_path to a list if needed
197+
if type(src_paths) != ListType:
198+
src_paths = [src_paths]
199+
# Extend src_paths wiht libraries_paths
200+
if libraries_paths is not None:
201+
src_paths.extend(libraries_paths)
202+
203+
# Build Directory
204+
if clean:
205+
if exists(build_path):
206+
rmtree(build_path)
207+
mkdir(build_path)
208+
209+
# Pass all params to the unified prepare_toolchain()
210+
toolchain = prepare_toolchain(src_paths, target, toolchain_name,
211+
macros=macros, options=options, clean=clean, jobs=jobs,
212+
notify=notify, silent=silent, verbose=verbose, extra_verbose=extra_verbose, config=config)
213+
214+
# The first path will give the name to the library
215+
if name is None:
216+
name = basename(normpath(abspath(src_paths[0])))
217+
toolchain.info("Building project %s (%s, %s)" % (name, toolchain.target.name, toolchain_name))
218+
219+
# Initialize reporting
177220
if report != None:
178221
start = time()
179-
180222
# If project_id is specified, use that over the default name
181223
id_name = project_id.upper() if project_id else name.upper()
182224
description = project_description if project_description else name
183-
vendor_label = target.extra_labels[0]
184-
cur_result = None
185-
prep_report(report, target.name, toolchain_name, id_name)
186-
cur_result = create_result(target.name, toolchain_name, id_name, description)
187-
225+
vendor_label = toolchain.target.extra_labels[0]
226+
prep_report(report, toolchain.target.name, toolchain_name, id_name)
227+
cur_result = create_result(toolchain.target.name, toolchain_name, id_name, description)
188228
if properties != None:
189-
prep_properties(properties, target.name, toolchain_name, vendor_label)
229+
prep_properties(properties, toolchain.target.name, toolchain_name, vendor_label)
190230

191231
try:
192-
# Scan src_path and libraries_paths for resources
193-
resources = toolchain.scan_resources(src_paths[0])
194-
for path in src_paths[1:]:
195-
resources.add(toolchain.scan_resources(path))
196-
if libraries_paths is not None:
197-
src_paths.extend(libraries_paths)
198-
for path in libraries_paths:
199-
resources.add(toolchain.scan_resources(path))
232+
# Call unified scan_resources
233+
resources = scan_resources(src_paths, toolchain, inc_dirs=inc_dirs)
200234

235+
# Change linker script if specified
201236
if linker_script is not None:
202237
resources.linker_script = linker_script
203238

204-
# Build Directory
205-
if clean:
206-
if exists(build_path):
207-
rmtree(build_path)
208-
mkdir(build_path)
209-
210-
# We need to add if necessary additional include directories
211-
if inc_dirs:
212-
if type(inc_dirs) == ListType:
213-
resources.inc_dirs.extend(inc_dirs)
214-
else:
215-
resources.inc_dirs.append(inc_dirs)
216-
217-
# Load resources into the config system which might expand/modify resources based on config data
218-
resources = config.load_resources(resources)
219-
220-
# Set the toolchain's configuration data
221-
toolchain.set_config_data(config.get_config_data())
222-
223239
# Compile Sources
224240
objects = toolchain.compile_sources(resources, build_path, resources.inc_dirs)
225241
resources.objects.extend(objects)
@@ -260,117 +276,67 @@ def build_project(src_path, build_path, target, toolchain_name,
260276

261277
def build_library(src_paths, build_path, target, toolchain_name,
262278
dependencies_paths=None, options=None, name=None, clean=False, archive=True,
263-
notify=None, verbose=False, macros=None, inc_dirs=None, inc_dirs_ext=None,
279+
notify=None, verbose=False, macros=None, inc_dirs=None,
264280
jobs=1, silent=False, report=None, properties=None, extra_verbose=False,
265281
project_id=None):
266-
""" src_path: the path of the source directory
282+
""" Prepares resource related objects - toolchain, target, config
283+
src_paths: the paths to source directories
267284
build_path: the path of the build directory
268285
target: ['LPC1768', 'LPC11U24', 'LPC2368']
269-
toolchain: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR']
270-
library_paths: List of paths to additional libraries
286+
toolchain_name: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR']
271287
clean: Rebuild everything if True
272288
notify: Notify function for logs
273289
verbose: Write the actual tools command lines if True
274290
inc_dirs: additional include directories which should be included in build
275-
inc_dirs_ext: additional include directories which should be copied to library directory
276291
"""
292+
293+
# Convert src_path to a list if needed
277294
if type(src_paths) != ListType:
278295
src_paths = [src_paths]
279296

280-
# The first path will give the name to the library
281-
project_name = basename(src_paths[0] if src_paths[0] != "." and src_paths[0] != "./" else getcwd())
282-
if name is None:
283-
# We will use default project name based on project folder name
284-
name = project_name
297+
# Build path
298+
if archive:
299+
# Use temp path when building archive
300+
tmp_path = join(build_path, '.temp')
301+
mkdir(tmp_path)
302+
else:
303+
tmp_path = build_path
285304

286-
# If the configuration object was not yet created, create it now
287-
config = Config(target, src_paths)
305+
# Pass all params to the unified prepare_toolchain()
306+
toolchain = prepare_toolchain(src_paths, target, toolchain_name,
307+
macros=macros, options=options, clean=clean, jobs=jobs,
308+
notify=notify, silent=silent, verbose=verbose, extra_verbose=extra_verbose)
288309

289-
# If the 'target' argument is a string, convert it to a target instance
290-
if isinstance(target, basestring):
291-
try:
292-
target = TARGET_MAP[target]
293-
except KeyError:
294-
raise KeyError("Target '%s' not found" % target)
310+
# The first path will give the name to the library
311+
if name is None:
312+
name = basename(normpath(abspath(src_paths[0])))
313+
toolchain.info("Building library %s (%s, %s)" % (name, toolchain.target.name, toolchain_name))
295314

315+
# Initialize reporting
296316
if report != None:
297317
start = time()
298-
299318
# If project_id is specified, use that over the default name
300319
id_name = project_id.upper() if project_id else name.upper()
301320
description = name
302-
vendor_label = target.extra_labels[0]
303-
cur_result = None
304-
prep_report(report, target.name, toolchain_name, id_name)
305-
cur_result = create_result(target.name, toolchain_name, id_name, description)
306-
321+
vendor_label = toolchain.target.extra_labels[0]
322+
prep_report(report, toolchain.target.name, toolchain_name, id_name)
323+
cur_result = create_result(toolchain.target.name, toolchain_name, id_name, description)
307324
if properties != None:
308-
prep_properties(properties, target.name, toolchain_name, vendor_label)
325+
prep_properties(properties, toolchain.target.name, toolchain_name, vendor_label)
309326

310327
for src_path in src_paths:
311328
if not exists(src_path):
312329
error_msg = "The library source folder does not exist: %s", src_path
313-
314330
if report != None:
315331
cur_result["output"] = error_msg
316332
cur_result["result"] = "FAIL"
317333
add_result_to_report(report, cur_result)
318-
319334
raise Exception(error_msg)
320335

321336
try:
322-
# Toolchain instance
323-
toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent, extra_verbose=extra_verbose)
324-
toolchain.VERBOSE = verbose
325-
toolchain.jobs = jobs
326-
toolchain.build_all = clean
327-
328-
toolchain.info("Building library %s (%s, %s)" % (name, target.name, toolchain_name))
329-
330-
# Scan Resources
331-
resources = None
332-
for path in src_paths:
333-
# Scan resources
334-
resource = toolchain.scan_resources(path)
335-
336-
# Extend resources collection
337-
if not resources:
338-
resources = resource
339-
else:
340-
resources.add(resource)
341-
342-
# We need to add if necessary additional include directories
343-
if inc_dirs:
344-
if type(inc_dirs) == ListType:
345-
resources.inc_dirs.extend(inc_dirs)
346-
else:
347-
resources.inc_dirs.append(inc_dirs)
348-
349-
# Add extra include directories / files which are required by library
350-
# This files usually are not in the same directory as source files so
351-
# previous scan will not include them
352-
if inc_dirs_ext is not None:
353-
for inc_ext in inc_dirs_ext:
354-
resources.add(toolchain.scan_resources(inc_ext))
355-
356-
# Dependencies Include Paths
357-
if dependencies_paths is not None:
358-
for path in dependencies_paths:
359-
lib_resources = toolchain.scan_resources(path)
360-
resources.inc_dirs.extend(lib_resources.inc_dirs)
361-
362-
if archive:
363-
# Use temp path when building archive
364-
tmp_path = join(build_path, '.temp')
365-
mkdir(tmp_path)
366-
else:
367-
tmp_path = build_path
368-
369-
# Load resources into the config system which might expand/modify resources based on config data
370-
resources = config.load_resources(resources)
337+
# Call unified scan_resources
338+
resources = scan_resources(src_paths, toolchain, dependencies_paths=dependencies_paths, inc_dirs=inc_dirs)
371339

372-
# Set the toolchain's configuration data
373-
toolchain.set_config_data(config.get_config_data())
374340

375341
# Copy headers, objects and static libraries - all files needed for static lib
376342
toolchain.copy_files(resources.headers, build_path, resources=resources)

tools/toolchains/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ def __init__(self, target, options=None, notify=None, macros=None, silent=False,
248248
# Labels generated from toolchain and target rules/features (used for selective build)
249249
self.labels = None
250250

251+
# This will hold the initialized config object
252+
self.config = None
253+
251254
# This will hold the configuration data (as returned by Config.get_config_data())
252255
self.config_data = None
253256

0 commit comments

Comments
 (0)