Skip to content

Commit e9a67a2

Browse files
committed
swift: Add swift_implicit_main target kwarg
The '-parse-as-library' compiler option forbids emitting top-level statements as part of an implicitly generated main function. This happens either in Swift modules consisting of only one file, or modules containing a 'main.swift' file. As a consequence, library targets should usually have this argument applied in order to not cause duplicate main symbols when linking the final executable. This is the new default behavior. Sometimes it is necessary to override this behavior, for example in case your Swift executable has a struct annotated with @main, or you have an executable Swift target that gets its main function from elsewhere (for example, linked C code). For this, targets can be passed the 'swift_implicit_main' kwarg, either with 'auto', which specifies Swift's default behavior, or 'never', which passes the '-parse-as-library' flag.
1 parent 910bfb9 commit e9a67a2

File tree

8 files changed

+33
-2
lines changed

8 files changed

+33
-2
lines changed

mesonbuild/backend/ninjabackend.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,6 +2220,8 @@ def generate_swift_target(self, target) -> None:
22202220
compile_args = self.generate_basic_compiler_args(target, swiftc)
22212221
compile_args += swiftc.get_compile_only_args()
22222222
compile_args += swiftc.get_module_args(module_name)
2223+
if target.uses_swift_parse_as_library_args():
2224+
compile_args += swiftc.get_library_args()
22232225
for i in reversed(target.get_include_dirs()):
22242226
basedir = i.get_curdir()
22252227
for d in i.get_incdirs():

mesonbuild/build.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class DFeatures(TypedDict):
7575
vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'}
7676
rust_kwargs = {'rust_crate_type', 'rust_dependency_map'}
7777
cs_kwargs = {'resources', 'cs_args'}
78+
swift_kwargs = {'swift_implicit_main'}
7879

7980
buildtarget_kwargs = {
8081
'build_by_default',
@@ -110,7 +111,8 @@ class DFeatures(TypedDict):
110111
pch_kwargs |
111112
vala_kwargs |
112113
rust_kwargs |
113-
cs_kwargs)
114+
cs_kwargs |
115+
swift_kwargs)
114116

115117
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie', 'vs_module_defs'}
116118
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'}
@@ -1233,6 +1235,13 @@ def process_kwargs(self, kwargs):
12331235
raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.')
12341236
self.rust_dependency_map = rust_dependency_map
12351237

1238+
self.swift_implicit_main = kwargs.get('swift_implicit_main', '')
1239+
permitted = {'', 'auto', 'never'}
1240+
if self.swift_implicit_main not in permitted:
1241+
raise InvalidArguments(
1242+
'Invalid value for swift_implicit_main {!r}: must be one of {}'
1243+
.format(self.swift_implicit_main, ', '.join(repr(x) for x in permitted)))
1244+
12361245
def _extract_pic_pie(self, kwargs: T.Dict[str, T.Any], arg: str, option: str) -> bool:
12371246
# Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags
12381247
all_flags = self.extra_args['c'] + self.extra_args['cpp']
@@ -1649,6 +1658,12 @@ def uses_rust_abi(self) -> bool:
16491658
def uses_fortran(self) -> bool:
16501659
return 'fortran' in self.compilers
16511660

1661+
def uses_swift_parse_as_library_args(self) -> bool:
1662+
if self.swift_implicit_main == '':
1663+
return isinstance(self, (StaticLibrary, SharedLibrary))
1664+
else:
1665+
return self.swift_implicit_main == 'never'
1666+
16521667
def get_using_msvc(self) -> bool:
16531668
'''
16541669
Check if the dynamic linker is MSVC. Used by Executable, StaticLibrary,

mesonbuild/compilers/swift.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ def get_working_directory_args(self, path: str) -> T.Optional[T.List[str]]:
121121

122122
return ['-working-directory', path]
123123

124+
def get_library_args(self) -> T.List[str]:
125+
return ['-parse-as-library']
126+
124127
def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str],
125128
build_dir: str) -> T.List[str]:
126129
for idx, i in enumerate(parameter_list):

mesonbuild/interpreter/type_checking.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ def _name_suffix_validator(arg: T.Optional[T.Union[str, T.List]]) -> T.Optional[
613613
default={},
614614
since='1.2.0',
615615
),
616+
KwargInfo('swift_implicit_main', str, default='', validator=in_set_validator({'', 'auto', 'never'}), since='1.7.99'),
616617
KwargInfo('build_rpath', str, default='', since='0.42.0'),
617618
KwargInfo(
618619
'gnu_symbol_visibility',
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import SingleFile
2+
3+
callMe()
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
project('single-file library', 'swift')
2+
3+
lib = static_library('SingleFile', 'singlefile.swift')
4+
executable('program', 'main.swift', link_with: [lib])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public func callMe() {}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
print("test")
1+
public func callMe() {
2+
print("test")
3+
}

0 commit comments

Comments
 (0)