Skip to content

Commit d81c12f

Browse files
vvmnnnkvmarcrasi
authored and
marcrasi
committed
Fix %install issues with modulemaps (#58)
1 parent 1e08b1d commit d81c12f

File tree

2 files changed

+72
-12
lines changed

2 files changed

+72
-12
lines changed

register.py

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def make_kernel_env(args):
5656
kernel_env['LD_LIBRARY_PATH'] = '%s/usr/lib/swift/linux' % args.swift_toolchain
5757
kernel_env['REPL_SWIFT_PATH'] = '%s/usr/bin/repl_swift' % args.swift_toolchain
5858
kernel_env['SWIFT_BUILD_PATH'] = '%s/usr/bin/swift-build' % args.swift_toolchain
59+
kernel_env['SWIFT_PACKAGE_PATH'] = '%s/usr/bin/swift-package' % args.swift_toolchain
5960
elif platform.system() == 'Darwin':
6061
kernel_env['PYTHONPATH'] = '%s/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python' % args.swift_toolchain
6162
kernel_env['LD_LIBRARY_PATH'] = '%s/usr/lib/swift/macosx' % args.swift_toolchain
@@ -118,6 +119,10 @@ def validate_kernel_env(kernel_env):
118119
not os.path.isfile(kernel_env['SWIFT_BUILD_PATH']):
119120
raise Exception('swift-build binary not found at %s' %
120121
kernel_env['SWIFT_BUILD_PATH'])
122+
if 'SWIFT_PACKAGE_PATH' in kernel_env and \
123+
not os.path.isfile(kernel_env['SWIFT_PACKAGE_PATH']):
124+
raise Exception('swift-package binary not found at %s' %
125+
kernel_env['SWIFT_PACKAGE_PATH'])
121126
if 'PYTHON_LIBRARY' in kernel_env and \
122127
not os.path.isfile(kernel_env['PYTHON_LIBRARY']):
123128
raise Exception('python library not found at %s' %

swift_kernel.py

+67-12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import textwrap
3131
import time
3232
import threading
33+
import sqlite3
34+
import json
3335

3436
from ipykernel.kernelbase import Kernel
3537
from jupyter_client.jsonutil import squash_dates
@@ -494,6 +496,12 @@ def _install_packages(self, packages, swiftpm_flags):
494496
'Install Error: Cannot install packages because '
495497
'SWIFT_BUILD_PATH is not specified.')
496498

499+
swift_package_path = os.environ.get('SWIFT_PACKAGE_PATH')
500+
if swift_package_path is None:
501+
raise PackageInstallException(
502+
'Install Error: Cannot install packages because '
503+
'SWIFT_PACKAGE_PATH is not specified.')
504+
497505
swift_import_search_path = os.environ.get('SWIFT_IMPORT_SEARCH_PATH')
498506
if swift_import_search_path is None:
499507
raise PackageInstallException(
@@ -591,27 +599,74 @@ def _install_packages(self, packages, swiftpm_flags):
591599

592600
# == Copy .swiftmodule and modulemap files to SWIFT_IMPORT_SEARCH_PATH ==
593601

594-
for filename in glob.glob(os.path.join(bin_dir, '*.swiftmodule')):
602+
build_db_file = os.path.join(package_base_path, '.build', 'build.db')
603+
if not os.path.exists(build_db_file):
604+
raise PackageInstallException('build.db is missing')
605+
606+
# Execute swift-package show-dependencies to get all dependencies' paths
607+
dependencies_result = subprocess.run(
608+
[swift_package_path, 'show-dependencies', '--format', 'json'],
609+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
610+
cwd=package_base_path)
611+
dependencies_json = dependencies_result.stdout.decode('utf8')
612+
dependencies_obj = json.loads(dependencies_json)
613+
614+
def flatten_deps_paths(dep):
615+
paths = []
616+
paths.append(dep["path"])
617+
if dep["dependencies"]:
618+
for d in dep["dependencies"]:
619+
paths.extend(flatten_deps_paths(d))
620+
return paths
621+
622+
# Make list of paths where we expect .swiftmodule and .modulemap files of dependencies
623+
dependencies_paths = [package_base_path]
624+
dependencies_paths = flatten_deps_paths(dependencies_obj)
625+
dependencies_paths = list(set(dependencies_paths))
626+
627+
def is_valid_dependency(path):
628+
for p in dependencies_paths:
629+
if path.startswith(p): return True
630+
return False
631+
632+
# Query to get build files list from build.db
633+
# SUBSTR because string starts with "N" (why?)
634+
SQL_FILES_SELECT = "SELECT SUBSTR(key, 2) FROM 'key_names' WHERE key LIKE ?"
635+
636+
# Connect to build.db
637+
db_connection = sqlite3.connect(build_db_file)
638+
cursor = db_connection.cursor()
639+
640+
# Process *.swiftmodules files
641+
cursor.execute(SQL_FILES_SELECT, ['%.swiftmodule'])
642+
swift_modules = [row[0] for row in cursor.fetchall() if is_valid_dependency(row[0])]
643+
for filename in swift_modules:
595644
shutil.copy(filename, swift_import_search_path)
596645

597-
# The modulemap files appear in a few different places. Add all of
598-
# them.
599-
# TODO: Figure out if there is a principled way to figure out where
600-
# all the modulemap files are.
601-
modulemap_files = glob.glob(
602-
os.path.join(bin_dir, '**/module.modulemap'), recursive=True)
603-
modulemap_files += glob.glob(
604-
os.path.join(package_base_path,
605-
'.build/checkouts/**/module.modulemap'),
606-
recursive=True)
646+
# Process modulemap files
647+
cursor.execute(SQL_FILES_SELECT, ['%/module.modulemap'])
648+
modulemap_files = [row[0] for row in cursor.fetchall() if is_valid_dependency(row[0])]
607649
for index, filename in enumerate(modulemap_files):
608650
# Create a separate directory for each modulemap file because the
609651
# ClangImporter requires that they are all named
610652
# "module.modulemap".
611653
modulemap_dest = os.path.join(swift_import_search_path,
612654
'modulemap-%d' % index)
613655
os.makedirs(modulemap_dest, exist_ok=True)
614-
shutil.copy(filename, modulemap_dest)
656+
src_folder, src_filename = os.path.split(filename)
657+
dst_path = os.path.join(modulemap_dest, src_filename)
658+
# Make all relative header paths in module.modulemap absolute
659+
# because we copy file to different location
660+
with open(filename, encoding='utf8') as file:
661+
modulemap_contents = file.read()
662+
modulemap_contents = re.sub(
663+
r'header\s+"(.*?)"',
664+
lambda m: 'header "%s"' %
665+
(m.group(1) if os.path.isabs(m.group(1)) else os.path.abspath(os.path.join(src_folder, m.group(1)))),
666+
modulemap_contents
667+
)
668+
with open(dst_path, 'w', encoding='utf8') as outfile:
669+
outfile.write(modulemap_contents)
615670

616671
# == dlopen the shared lib ==
617672

0 commit comments

Comments
 (0)