Skip to content

Commit e55dc9b

Browse files
committed
feat: enable swift compilation
1 parent aaf33c3 commit e55dc9b

File tree

8 files changed

+824
-72
lines changed

8 files changed

+824
-72
lines changed

gyp/pylib/gyp/generator/ninja.py

Lines changed: 385 additions & 10 deletions
Large diffs are not rendered by default.

gyp/pylib/gyp/mac_tool.py

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from __future__ import print_function
1212

13+
import errno
1314
import fcntl
1415
import fnmatch
1516
import glob
@@ -190,7 +191,7 @@ def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys):
190191

191192
# Go through all the environment variables and replace them as variables in
192193
# the file.
193-
IDENT_RE = re.compile(r"[_/\s]")
194+
IDENT_RE = re.compile(r"[_/\s_-]")
194195
for key in os.environ:
195196
if key.startswith("_"):
196197
continue
@@ -357,13 +358,34 @@ def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers):
357358
filelist[os.path.join(framework_name, filename)] = header
358359
WriteHmap(out, filelist)
359360

361+
def ExecCompileSwiftFrameworkHeaderMap(self, out, framework, *all_headers):
362+
framework_name = os.path.basename(framework).split(".")[0]
363+
all_headers = [os.path.abspath(header) for header in all_headers]
364+
filelist = {}
365+
for header in all_headers:
366+
filename = os.path.basename(header)
367+
filelist[filename] = header
368+
filelist[os.path.join(framework_name, filename)] = header
369+
WriteHmap(out, filelist)
370+
360371
def ExecCopyIosFrameworkHeaders(self, framework, *copy_headers):
361372
header_path = os.path.join(framework, "Headers")
362373
if not os.path.exists(header_path):
363374
os.makedirs(header_path)
364375
for header in copy_headers:
365376
shutil.copy(header, os.path.join(header_path, os.path.basename(header)))
366377

378+
def ExecSymlinkSwiftFrameworkComponents(self, framework):
379+
headers_path = os.path.join(framework, "Headers")
380+
pwd = os.getcwd()
381+
headers_symlink_path = os.path.join(pwd, framework, "Versions", "A", "Headers")
382+
os.symlink(headers_symlink_path, headers_path)
383+
384+
modules_path = os.path.join(framework, "Modules")
385+
pwd = os.getcwd()
386+
modules_symlink_path = os.path.join(pwd, framework, "Versions", "A", "Modules")
387+
os.symlink(modules_symlink_path, modules_path)
388+
367389
def ExecCompileXcassets(self, keys, *inputs):
368390
"""Compiles multiple .xcassets files into a single .car file.
369391
@@ -436,6 +458,63 @@ def ExecCompileXcassets(self, keys, *inputs):
436458
command_line.extend(map(os.path.abspath, inputs))
437459
subprocess.check_call(command_line)
438460

461+
def _EnsureDirExists(self, dir_path):
462+
if not os.path.exists(dir_path):
463+
try:
464+
os.makedirs(dir_path)
465+
except OSError as exc:
466+
if exc.errno != errno.EEXIST:
467+
raise
468+
469+
def _MakeStamp(self, stamp):
470+
self._EnsureDirExists(os.path.dirname(stamp))
471+
subprocess.check_call(["touch", stamp])
472+
473+
def ExecCopySwiftLibs(self, executable_path, platform, dst_path, codesign_key,
474+
stamp):
475+
args = [
476+
"xcrun", "swift-stdlib-tool", "--copy",
477+
"--scan-executable", executable_path,
478+
"--platform", platform,
479+
"--destination", dst_path,
480+
"--filter-for-swift-os"
481+
]
482+
if codesign_key:
483+
args.extend(["--sign", codesign_key])
484+
485+
env = {"PATH" : os.environ.get("PATH", "")}
486+
p = subprocess.Popen(args, env=env)
487+
retcode = p.wait()
488+
if retcode != 0:
489+
raise subprocess.CalledProcessError(retcode, args)
490+
491+
self._MakeStamp(stamp)
492+
493+
def ExecBuildModuleMapFile(self, module_name, umbrella_header, map_file,
494+
stamp):
495+
self._EnsureDirExists(os.path.dirname(map_file))
496+
with open(map_file, "w") as f:
497+
f.write(
498+
"framework module %s {\n"
499+
" umbrella header \"%s\"\n"
500+
" export *\n"
501+
" module * { export * }\n"
502+
"}\n" % (module_name, umbrella_header))
503+
504+
self._MakeStamp(stamp)
505+
506+
def ExecAppendSwiftToModuleMapFile(self, module_name, swift_header, map_file,
507+
stamp):
508+
self._EnsureDirExists(os.path.dirname(map_file))
509+
with open(map_file, "a") as f:
510+
f.write(
511+
"module %s.Swift {\n"
512+
" requires objc\n"
513+
" header \"%s\"\n"
514+
"}\n" % (module_name, swift_header))
515+
516+
self._MakeStamp(stamp)
517+
439518
def ExecMergeInfoPlist(self, output, *inputs):
440519
"""Merge multiple .plist files into a single .plist file."""
441520
merged_plist = {}

gyp/pylib/gyp/xcode_emulation.py

Lines changed: 201 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ def _AppendPlatformVersionMinFlags(self, lst):
571571
lst, "IPHONEOS_DEPLOYMENT_TARGET", "-miphoneos-version-min=%s"
572572
)
573573

574-
def GetCflags(self, configname, arch=None):
574+
def GetCflags(self, configname, gyp_to_build_path, arch=None):
575575
"""Returns flags that need to be added to .c, .cc, .m, and .mm
576576
compilations."""
577577
# This functions (and the similar ones below) do not offer complete
@@ -590,6 +590,15 @@ def GetCflags(self, configname, arch=None):
590590
if self._Test("CLANG_WARN_CONSTANT_CONVERSION", "YES", default="NO"):
591591
cflags.append("-Wconstant-conversion")
592592

593+
if self._AreModulesEnabled():
594+
cflags.append("-fmodules")
595+
module_cache_path = self._Settings().get(
596+
"CLANG_MODULE_CACHE_PATH", self._GetDefaultClangModuleCachePath())
597+
if arch:
598+
module_cache_path = os.path.join(module_cache_path, arch)
599+
cflags.append("-fmodules-cache-path=\'%s\'" % module_cache_path)
600+
cflags.append("-F.")
601+
593602
if self._Test("GCC_CHAR_IS_UNSIGNED_CHAR", "YES", default="NO"):
594603
cflags.append("-funsigned-char")
595604

@@ -691,11 +700,185 @@ def GetCflags(self, configname, arch=None):
691700
config = self.spec["configurations"][self.configname]
692701
framework_dirs = config.get("mac_framework_dirs", [])
693702
for directory in framework_dirs:
694-
cflags.append("-F" + directory.replace("$(SDKROOT)", framework_root))
703+
cflags.append("-F" + gyp_to_build_path(directory))
695704

696705
self.configname = None
697706
return cflags
698707

708+
def AreModulesEnabled(self, configname):
709+
self.configname = configname
710+
res = self._AreModulesEnabled()
711+
self.configname = None
712+
return res
713+
714+
def _AreModulesEnabled(self):
715+
res = self._Test("CLANG_ENABLE_MODULES", "YES", default="NO")
716+
return res
717+
718+
def IsModuleDefined(self, configname):
719+
self.configname = configname
720+
res = self._IsModuleDefined()
721+
self.configname = None
722+
return res
723+
724+
def _IsModuleDefined(self):
725+
res = self._Test("DEFINES_MODULE", "YES", default="NO")
726+
return res
727+
728+
def IsSwiftWMOEnabled(self, configname):
729+
self.configname = configname
730+
res = self._IsSwiftWMOEnabled()
731+
self.configname = None
732+
return res
733+
734+
def _IsSwiftWMOEnabled(self):
735+
return self._Test("SWIFT_OPTIMIZATION_LEVEL", "-Owholemodule", default="-O")
736+
737+
def GetProductModuleName(self, configname):
738+
self.configname = configname
739+
swift_module_name = self._GetProductModuleName()
740+
self.configname = None
741+
return swift_module_name
742+
743+
def _GetProductModuleName(self):
744+
default_module_name = self.spec["target_name"].replace("-", "_")
745+
return self._Settings().get(
746+
"PRODUCT_MODULE_NAME", default_module_name)
747+
748+
def GetSwiftHeaderPath(self, configname, gyp_path_to_build_path, arch=None):
749+
self.configname = configname
750+
swift_header_path = self._GetSwiftHeaderPath(gyp_path_to_build_path, arch)
751+
self.configname = None
752+
return swift_header_path
753+
754+
def _GetSwiftHeaderPath(self, gyp_path_to_build_path, arch):
755+
swift_header_name = self._Settings().get(
756+
"SWIFT_OBJC_INTERFACE_HEADER_NAME",
757+
self._GetProductModuleName() + "-Swift.h")
758+
# SWIFT_OBJC_INTERFACE_HEADER_NAME must just a file name without path
759+
assert not os.path.dirname(swift_header_name)
760+
if arch:
761+
swift_header_name = re.sub(r"\.h$", "." + arch + ".h", swift_header_name)
762+
swift_header_path = os.path.join("$!INTERMEDIATE_DIR", swift_header_name)
763+
swift_header_path = gyp_path_to_build_path(swift_header_path)
764+
return swift_header_path
765+
766+
def _GetCommonLibsPath(self):
767+
developer_dir = subprocess.check_output(["xcode-select", "-p"]).strip().decode(sys.stdout.encoding)
768+
base_toolchain_path = os.path.join(
769+
developer_dir, "Toolchains/XcodeDefault.xctoolchain")
770+
base_toolchain_path = os.path.normpath(base_toolchain_path)
771+
772+
libs_path = os.path.join(base_toolchain_path, "usr", "lib")
773+
assert os.path.exists(libs_path)
774+
return libs_path
775+
776+
def GetPlatform(self, configname):
777+
sdk_path_basename = os.path.basename(self._SdkPath(configname))
778+
if sdk_path_basename.lower().startswith("iphonesimulator"):
779+
platform = "iphonesimulator"
780+
elif sdk_path_basename.lower().startswith("iphoneos"):
781+
platform = "iphoneos"
782+
elif sdk_path_basename.lower().startswith("macosx"):
783+
platform = "macosx"
784+
else:
785+
assert False, "Unexpected platform"
786+
787+
return platform
788+
789+
def _GetDefaultClangModuleCachePath(self):
790+
return os.path.join(os.path.expanduser("~"),
791+
"Library/Developer/Xcode/DerivedData/ModuleCache")
792+
793+
def _GetSwiftCommonFlags(self, gyp_path_to_build_path, arch):
794+
assert arch
795+
796+
swift_flags = []
797+
swift_flags.append("-enable-objc-interop")
798+
799+
if self._IsModuleDefined():
800+
swift_flags.append("-import-underlying-module")
801+
802+
self._Appendf(swift_flags, "IPHONEOS_DEPLOYMENT_TARGET",
803+
"-target " + arch + "-apple-ios%s")
804+
self._Appendf(swift_flags, "MACOSX_DEPLOYMENT_TARGET",
805+
"-target " + arch + "-apple-macosx%s")
806+
807+
swift_flags.append("-sdk " + self._SdkPath())
808+
809+
swift_flags.append("-g")
810+
811+
swift_flags.append("-parse-as-library")
812+
813+
self._Appendf(swift_flags,
814+
"CLANG_MODULE_CACHE_PATH",
815+
"-module-cache-path \"%s\"",
816+
self._GetDefaultClangModuleCachePath())
817+
818+
swift_flags.append("-module-name " + self._GetProductModuleName())
819+
820+
if self._Settings().get("SWIFT_OBJC_BRIDGING_HEADER"):
821+
import_header = self._Settings().get("SWIFT_OBJC_BRIDGING_HEADER")
822+
import_header = gyp_path_to_build_path(import_header)
823+
swift_flags.append("-import-objc-header \"" + import_header + "\"")
824+
825+
config = self.spec["configurations"][self.configname]
826+
framework_dirs = config.get("mac_framework_dirs", [])
827+
sdk_root = self._SdkPath()
828+
for directory in framework_dirs:
829+
swift_flags.append("-F" + gyp_path_to_build_path(directory))
830+
831+
swift_flags.append("-F.")
832+
833+
swift_flags.append("-I.")
834+
for i in config.get("include_dirs", []):
835+
swift_flags.append("-I" + gyp_path_to_build_path(i))
836+
837+
return swift_flags
838+
839+
def GetBundleFrameworksFolderPath(self):
840+
return os.path.join(self.GetBundleContentsFolderPath(), "Frameworks")
841+
842+
def GetBundlePublicHeadersFolderPath(self):
843+
return os.path.join(self.GetBundleContentsFolderPath(), "Headers")
844+
845+
def GetBundlePrivateHeadersFolderPath(self):
846+
return os.path.join(self.GetBundleContentsFolderPath(), "PrivateHeaders")
847+
848+
def GetBundleModulesFolderPath(self):
849+
return os.path.join(self.GetBundleContentsFolderPath(), "Modules")
850+
851+
def GetSwiftCompileFlags(self, configname, gyp_path_to_build_path, arch):
852+
self.configname = configname
853+
854+
swift_flags = self._GetSwiftCommonFlags(gyp_path_to_build_path, arch)
855+
856+
if self._IsSwiftWMOEnabled():
857+
swift_flags.append("-O")
858+
else:
859+
self._Appendf(swift_flags, "SWIFT_OPTIMIZATION_LEVEL", "%s", "-O")
860+
861+
self.configname = None
862+
return swift_flags
863+
864+
def GetSwiftMergeFlags(self, configname, gyp_path_to_build_path, arch):
865+
self.configname = configname
866+
867+
swift_flags = self._GetSwiftCommonFlags(gyp_path_to_build_path, arch)
868+
869+
self.configname = None
870+
return swift_flags
871+
872+
def GetSwiftLdflags(self, arch_module_path):
873+
ldflags = []
874+
875+
# Feels bad but necessary for Nan and n-api.
876+
ldflags.append("-undefined dynamic_lookup")
877+
878+
ldflags.append("-Xlinker -add_ast_path -Xlinker " + arch_module_path)
879+
ldflags.append("-L/usr/lib/swift")
880+
return ldflags
881+
699882
def GetCflagsC(self, configname):
700883
"""Returns flags that need to be added to .c, and .m compilations."""
701884
self.configname = configname
@@ -938,6 +1121,10 @@ def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
9381121
+ gyp_to_build_path(self._Settings()["ORDER_FILE"])
9391122
)
9401123

1124+
if "BUNDLE_LOADER" in self._Settings():
1125+
bundle_loader_path = gyp_to_build_path(self._Settings()["BUNDLE_LOADER"])
1126+
ldflags.append("-bundle_loader " + bundle_loader_path)
1127+
9411128
if arch is not None:
9421129
archs = [arch]
9431130
else:
@@ -958,15 +1145,16 @@ def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
9581145
ldflags.append("-install_name " + install_name.replace(" ", r"\ "))
9591146

9601147
for rpath in self._Settings().get("LD_RUNPATH_SEARCH_PATHS", []):
961-
ldflags.append("-Wl,-rpath," + rpath)
1148+
ldflags.append("-Xlinker -rpath -Xlinker " + rpath)
9621149

9631150
sdk_root = self._SdkPath()
9641151
if not sdk_root:
9651152
sdk_root = ""
9661153
config = self.spec["configurations"][self.configname]
9671154
framework_dirs = config.get("mac_framework_dirs", [])
9681155
for directory in framework_dirs:
969-
ldflags.append("-F" + directory.replace("$(SDKROOT)", sdk_root))
1156+
ldflags.append("-F" + gyp_to_build_path(directory))
1157+
ldflags.append("-F.")
9701158

9711159
if self._IsXCTest():
9721160
platform_root = self._XcodePlatformPath(configname)
@@ -1213,6 +1401,13 @@ def _GetIOSPostbuilds(self, configname, output_binary):
12131401
)
12141402
return postbuilds
12151403

1404+
def GetCodeSignIdentityKey(self, configname):
1405+
if not self.isIOS:
1406+
return None
1407+
1408+
settings = self.xcode_settings[configname]
1409+
return self._GetIOSCodeSignIdentityKey(settings)
1410+
12161411
def _GetIOSCodeSignIdentityKey(self, settings):
12171412
identity = settings.get("CODE_SIGN_IDENTITY")
12181413
if not identity:
@@ -1701,6 +1896,8 @@ def GetMacInfoPlist(product_dir, xcode_settings, gyp_path_to_build_path):
17011896

17021897
return info_plist, dest_plist, defines, extra_env
17031898

1899+
def IsSwiftSupported():
1900+
return True
17041901

17051902
def _GetXcodeEnv(
17061903
xcode_settings, built_products_dir, srcroot, configuration, additional_settings=None

0 commit comments

Comments
 (0)