Skip to content

Commit 130a4d0

Browse files
committed
Add an option to create a source package
The new action 'package-src' can be used to create a source package consisting of: - The LLVM Embedded Toolchain for Arm repository - Patched LLVM and newlib repositories - Version information The build scripts cannot make use of the bundled LLVM and newlib repositories, this functionality will be added in a follow-up patch.
1 parent 288deb6 commit 130a4d0

File tree

4 files changed

+115
-46
lines changed

4 files changed

+115
-46
lines changed

scripts/build.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def parse_args_to_config() -> Config:
164164
' configure - write target configuration files\n'
165165
' package - create binary package\n'
166166
' all - perform all of the above\n'
167+
' package-src - create source package\n'
167168
' test - run tests\n'
168169
'Default: all')
169170
args = parser.parse_args()
@@ -353,12 +354,17 @@ def main() -> int:
353354
build_all(cfg)
354355
run_tests(cfg)
355356

356-
def do_package():
357+
def do_source_package():
357358
version.poplulate_commits(cfg.repos_dir)
358-
package.write_version_file(cfg, version)
359-
package.copy_samples(cfg)
360-
package.package_toolchain(cfg)
361-
run_or_skip(cfg, Action.PACKAGE, do_package, 'packaging')
359+
package.create_source_package(cfg, version)
360+
run_or_skip(cfg, Action.PACKAGE_SRC, do_source_package,
361+
'source package')
362+
363+
def do_binary_package():
364+
version.poplulate_commits(cfg.repos_dir)
365+
package.create_binary_package(cfg, version)
366+
run_or_skip(cfg, Action.PACKAGE, do_binary_package, 'binary package')
367+
362368
except util.ToolchainBuildError:
363369
# By this time the error must have already been logged
364370
return 1

scripts/config.py

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ class Action(enum.Enum):
112112
CONFIGURE = 'configure'
113113
PACKAGE = 'package'
114114
ALL = 'all'
115-
# The 'test' phase is not part of 'all'
115+
# The 'test' and 'package-src' phases are not part of 'all'
116116
TEST = 'test'
117+
PACKAGE_SRC = 'package-src'
117118

118119

119120
@enum.unique
@@ -256,30 +257,19 @@ def _default_target(self):
256257
return 'aarch64-none-elf'
257258
return None
258259

259-
def _fill_args(self, args: argparse.Namespace):
260-
if 'all' in args.variants:
261-
variant_names = LIBRARY_SPECS.keys()
262-
else:
263-
variant_names = set(args.variants)
264-
self.variants = [LIBRARY_SPECS[v] for v in sorted(variant_names)]
265-
260+
def _configure_actions(self, args: argparse.Namespace):
266261
if not args.actions or Action.ALL.value in args.actions:
262+
# Actions that are not part of the "ALL" action:
263+
exclude_from_all = [Action.ALL, Action.TEST, Action.PACKAGE_SRC]
267264
self.actions = set(action for action in Action
268-
if action not in (Action.ALL, Action.TEST))
269-
if Action.TEST.value in args.actions:
270-
self.actions.add(Action.TEST)
265+
if action not in exclude_from_all)
266+
for action in [Action.TEST, Action.PACKAGE_SRC]:
267+
if action.value in args.actions:
268+
self.actions.add(action)
271269
else:
272270
self.actions = set(Action(act_str) for act_str in args.actions)
273271

274-
self.default_target = self._default_target()
275-
276-
rev = args.revision
277-
self.revision = rev
278-
self.source_dir = os.path.abspath(args.source_dir)
279-
self.repos_dir = _assign_dir(args.repositories_dir, 'repos', rev)
280-
self.build_dir = _assign_dir(args.build_dir, 'build', rev)
281-
self.install_dir = _assign_dir(args.install_dir, 'install', rev)
282-
self.package_dir = os.path.abspath(args.package_dir)
272+
def _configure_toolchains(self, args: argparse.Namespace):
283273
# According to
284274
# https://docs.python.org/3.6/library/enum.html#using-a-custom-new:
285275
# "The __new__() method, if defined, is used during creation of the
@@ -296,15 +286,33 @@ def _fill_args(self, args: argparse.Namespace):
296286
native_toolchain_dir = os.path.abspath(args.native_toolchain_dir)
297287
self.native_toolchain = Toolchain(native_toolchain_dir,
298288
native_toolchain_kind)
289+
290+
self.is_using_mingw = self.host_toolchain.kind == ToolchainKind.MINGW
291+
self.is_windows = self.is_using_mingw
292+
self.is_cross_compiling = (os.name == 'posix' and self.is_windows)
293+
294+
def _fill_args(self, args: argparse.Namespace):
295+
if 'all' in args.variants:
296+
variant_names = LIBRARY_SPECS.keys()
297+
else:
298+
variant_names = set(args.variants)
299+
self.variants = [LIBRARY_SPECS[v] for v in sorted(variant_names)]
300+
301+
self.default_target = self._default_target()
302+
303+
rev = args.revision
304+
self.revision = rev
305+
self.source_dir = os.path.abspath(args.source_dir)
306+
self.repos_dir = _assign_dir(args.repositories_dir, 'repos', rev)
307+
self.build_dir = _assign_dir(args.build_dir, 'build', rev)
308+
self.install_dir = _assign_dir(args.install_dir, 'install', rev)
309+
self.package_dir = os.path.abspath(args.package_dir)
299310
self.checkout_mode = CheckoutMode(args.checkout_mode)
300311
self.build_mode = BuildMode(args.build_mode)
301312

302-
is_using_mingw = self.host_toolchain.kind == ToolchainKind.MINGW
303-
is_windows = is_using_mingw
304-
305313
copy_runtime = CopyRuntime(args.copy_runtime_dlls)
306314
self.ask_copy_runtime_dlls = True
307-
if is_using_mingw:
315+
if self.is_using_mingw:
308316
self.ask_copy_runtime_dlls = (copy_runtime == CopyRuntime.ASK)
309317
if not self.ask_copy_runtime_dlls:
310318
self._copy_runtime_dlls = (copy_runtime == CopyRuntime.YES)
@@ -316,7 +324,7 @@ def _fill_args(self, args: argparse.Namespace):
316324
self._copy_runtime_dlls = False
317325

318326
if args.package_format is None:
319-
self.package_format = (PackageFormat.ZIP if is_windows else
327+
self.package_format = (PackageFormat.ZIP if self.is_windows else
320328
PackageFormat.TGZ)
321329
else:
322330
self.package_format = PackageFormat(args.package_format)
@@ -344,9 +352,6 @@ def _fill_inferred(self):
344352
join = os.path.join
345353
self.llvm_repo_dir = join(self.repos_dir, 'llvm.git')
346354
self.newlib_repo_dir = join(self.repos_dir, 'newlib.git')
347-
is_using_mingw = self.host_toolchain.kind == ToolchainKind.MINGW
348-
self.is_cross_compiling = (os.name == 'posix' and is_using_mingw)
349-
self.is_windows = is_using_mingw
350355
self.cmake_generator = 'Ninja' if self.use_ninja else 'Unix Makefiles'
351356
self.release_mode = self.revision != 'HEAD'
352357
if self.release_mode:
@@ -358,10 +363,14 @@ def _fill_inferred(self):
358363
self.version_string = now.strftime('%Y-%m-%d-%H:%M:%S')
359364
self.skip_reconfigure = self.build_mode == BuildMode.INCREMENTAL
360365
product_name = 'LLVMEmbeddedToolchainForArm'
361-
self.package_base_name = product_name + version_suffix
366+
self.bin_package_base_name = product_name + version_suffix
367+
self.src_package_base_name = product_name + version_suffix + '-src'
362368
self.target_llvm_dir = join(
363369
self.install_dir,
364370
'{}-{}'.format(product_name, self.revision))
371+
self.install_src_subdir = join(
372+
self.install_dir,
373+
'{}-{}-src'.format(product_name, self.revision))
365374
if self.is_cross_compiling:
366375
self.native_llvm_build_dir = join(self.build_dir, 'native-llvm')
367376
self.native_llvm_dir = join(self.install_dir, 'native-llvm')
@@ -377,5 +386,7 @@ def _fill_inferred(self):
377386

378387
def __init__(self, args: argparse.Namespace):
379388
self._copy_runtime_dlls = None
389+
self._configure_actions(args)
390+
self._configure_toolchains(args)
380391
self._fill_args(args)
381392
self._fill_inferred()

scripts/package.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626
import util
2727

2828

29-
def write_version_file(cfg: config.Config, version: repos.LLVMBMTC) -> None:
29+
def _write_version_file(cfg: config.Config, version: repos.LLVMBMTC,
30+
target_dir: str) -> None:
3031
"""Create VERSION.txt in the install directory."""
31-
dest = os.path.join(cfg.target_llvm_dir, 'VERSION.txt')
32+
dest = os.path.join(target_dir, 'VERSION.txt')
3233
if cfg.verbose:
3334
logging.info('Writing "%s" to %s', cfg.version_string, dest)
3435
lines = [cfg.version_string, '', 'Components:']
@@ -40,7 +41,7 @@ def write_version_file(cfg: config.Config, version: repos.LLVMBMTC) -> None:
4041
util.write_lines(lines, dest)
4142

4243

43-
def copy_samples(cfg: config.Config) -> None:
44+
def _copy_samples(cfg: config.Config) -> None:
4445
"""Copy code samples, filter out files that are not usable on the target
4546
platform."""
4647
src = os.path.join(cfg.source_dir, 'samples')
@@ -76,7 +77,7 @@ def _get_excluded_symlinks(cfg: config.Config) -> FrozenSet[str]:
7677
return frozenset(excludes)
7778

7879

79-
def _create_tarball(cfg: config.Config, dest_pkg: str) -> None:
80+
def _create_tarball(cfg: config.Config, src_dir: str, dest_pkg: str) -> None:
8081
"""Create a tarball package."""
8182
def reset_uid(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo:
8283
tarinfo.uid = tarinfo.gid = 0
@@ -88,7 +89,7 @@ def reset_uid(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo:
8889
exclude_set = _get_excluded_symlinks(cfg)
8990
dereference = True
9091
with tarfile.open(dest_pkg, 'w:gz') as dest:
91-
for root, _, files in os.walk(cfg.target_llvm_dir):
92+
for root, _, files in os.walk(src_dir):
9293
for fname in sorted(files):
9394
if fname in exclude_set:
9495
continue
@@ -102,11 +103,11 @@ def reset_uid(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo:
102103
filter=reset_uid)
103104

104105

105-
def _create_zip(cfg: config.Config, dest_pkg: str) -> None:
106+
def _create_zip(cfg: config.Config, src_dir: str, dest_pkg: str) -> None:
106107
"""Create a zip package."""
107108
exclude_set = _get_excluded_symlinks(cfg)
108109
with zipfile.ZipFile(dest_pkg, 'w', zipfile.ZIP_DEFLATED) as dest:
109-
for root, _, files in os.walk(cfg.target_llvm_dir):
110+
for root, _, files in os.walk(src_dir):
110111
for fname in files:
111112
if fname in exclude_set:
112113
continue
@@ -117,20 +118,39 @@ def _create_zip(cfg: config.Config, dest_pkg: str) -> None:
117118
dest.write(abs_path, arc_name)
118119

119120

120-
def package_toolchain(cfg: config.Config) -> None:
121-
"""Create a package with a newly built toolchain."""
121+
def _create_archive(cfg: config.Config, pkg_src_dir, pkg_dest_name) -> None:
122+
"""Create a package from a given directory."""
122123
if not os.path.exists(cfg.package_dir):
123124
os.makedirs(cfg.package_dir)
124125
format_mapping = {
125126
PackageFormat.TGZ: ('.tar.gz', _create_tarball),
126127
PackageFormat.ZIP: ('.zip', _create_zip),
127128
}
128129
package_ext, package_fn = format_mapping[cfg.package_format]
129-
dest_pkg = os.path.join(cfg.package_dir,
130-
cfg.package_base_name + package_ext)
130+
dest_pkg = os.path.join(cfg.package_dir, pkg_dest_name + package_ext)
131131
logging.info('Creating package %s', dest_pkg)
132132
try:
133-
package_fn(cfg, dest_pkg)
133+
package_fn(cfg, pkg_src_dir, dest_pkg)
134134
except RuntimeError as ex:
135135
logging.error('Failed to create %s', dest_pkg)
136136
raise util.ToolchainBuildError from ex
137+
138+
139+
def create_binary_package(cfg: config.Config, version: repos.LLVMBMTC) -> None:
140+
"""Create a binary package with a newly built toolchain."""
141+
_write_version_file(cfg, version, cfg.target_llvm_dir)
142+
_copy_samples(cfg)
143+
_create_archive(cfg, cfg.target_llvm_dir, cfg.bin_package_base_name)
144+
145+
146+
def create_source_package(cfg: config.Config, version: repos.LLVMBMTC) -> None:
147+
"""Create a source package with a newly built toolchain."""
148+
if os.path.exists(cfg.install_src_subdir):
149+
logging.info('Removing existing directory %s', cfg.install_src_subdir)
150+
shutil.rmtree(cfg.install_src_subdir)
151+
os.makedirs(cfg.install_src_subdir)
152+
repos.export_repository(cfg.source_dir, cfg.install_src_subdir, False)
153+
repos.export_toolchain_repositories(cfg.repos_dir, version,
154+
cfg.install_src_subdir)
155+
_write_version_file(cfg, version, cfg.install_src_subdir)
156+
_create_archive(cfg, cfg.install_src_subdir, cfg.src_package_base_name)

scripts/repos.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import argparse
2121
import logging
2222
import os
23+
import shutil
2324
import sys
2425
from typing import List, Mapping, Optional, Any
2526

@@ -143,6 +144,9 @@ def __repr__(self):
143144

144145
def poplulate_commits(self, repos_dir: str) -> None:
145146
"""Populate commit hashes from checked out repositoties."""
147+
# Check if commit hashes have already been set
148+
if all(module.status is not None for module in self.modules.values()):
149+
return
146150
status = get_repositories_status(repos_dir)
147151
for name, module in self.modules.items():
148152
if name not in status:
@@ -285,6 +289,34 @@ def clone_repositories(checkout_path: str, tc_version: LLVMBMTC,
285289
patch_repositories(checkout_path, tc_version, patches)
286290

287291

292+
def export_repository(src_repo_path: str, dest_repo_path: str,
293+
copy_untracked: bool = False) -> None:
294+
"""Copy the files of a checked out repository to a new directory. The copy
295+
will include unstaged changes and optionally untracked files if
296+
copy_untracked is True."""
297+
logging.info('Exporting "%s" to "%s"', src_repo_path, dest_repo_path)
298+
git_cmd = git.cmd.Git(src_repo_path)
299+
args = ['--cached']
300+
if copy_untracked:
301+
args.append('--other')
302+
for fname in git_cmd.ls_files(*args).splitlines():
303+
src_path = os.path.join(src_repo_path, fname)
304+
dest_path = os.path.join(dest_repo_path, fname)
305+
dest_dir = os.path.dirname(dest_path)
306+
if not os.path.exists(dest_dir):
307+
os.makedirs(dest_dir)
308+
shutil.copy2(src_path, dest_path, follow_symlinks=False)
309+
310+
311+
def export_toolchain_repositories(checkout_path: str, tc_version: LLVMBMTC,
312+
dest_path: str) -> None:
313+
"""Export all checked out repositories."""
314+
for repo_dir in tc_version.modules.keys():
315+
export_repository(os.path.join(checkout_path, repo_dir),
316+
os.path.join(dest_path, repo_dir),
317+
True)
318+
319+
288320
def freeze_repositories(checkout_path: str, version: str) -> None:
289321
"""Print a YAML compatible output of the repositories state."""
290322
statuses = get_repositories_status(checkout_path)

0 commit comments

Comments
 (0)