Skip to content

Commit fad110c

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 1b54239 commit fad110c

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'}
@@ -1214,6 +1216,13 @@ def process_kwargs(self, kwargs):
12141216
raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.')
12151217
self.rust_dependency_map = rust_dependency_map
12161218

1219+
self.swift_implicit_main = kwargs.get('swift_implicit_main', '')
1220+
permitted = {'', 'auto', 'never'}
1221+
if self.swift_implicit_main not in permitted:
1222+
raise InvalidArguments(
1223+
'Invalid value for swift_implicit_main {!r}: must be one of {}'
1224+
.format(self.swift_implicit_main, ', '.join(repr(x) for x in permitted)))
1225+
12171226
def _extract_pic_pie(self, kwargs: T.Dict[str, T.Any], arg: str, option: str) -> bool:
12181227
# Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags
12191228
all_flags = self.extra_args['c'] + self.extra_args['cpp']
@@ -1630,6 +1639,12 @@ def uses_rust_abi(self) -> bool:
16301639
def uses_fortran(self) -> bool:
16311640
return 'fortran' in self.compilers
16321641

1642+
def uses_swift_parse_as_library_args(self) -> bool:
1643+
if self.swift_implicit_main == '':
1644+
return isinstance(self, (StaticLibrary, SharedLibrary))
1645+
else:
1646+
return self.swift_implicit_main == 'never'
1647+
16331648
def get_using_msvc(self) -> bool:
16341649
'''
16351650
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)