Add support for building .swift files
This CL allow listing .swift files in sources of compiler target
(source_set, executable, static_library, shared_library). Mixing
with other types of source files is disallowed due to complexity
of implementation (difficult to decide in which order the files
need to be built).
This adds a new "swift" tool that must always list a .swiftmodule
file as output but can generate additional outputs (.h, .o, ...).
To support whole module optimisation, the tool can have partial
outputs (i.e. have 1:1 mapping between source and output) or not.
The .swiftmodule are propagated both to direct and public deps
for generation of module search path (expanded by {{module_dirs}})
and to linkable target (expanded as {{modules}}) to embed the
module AST in the linked binary.
Based on the investigation at https://goto.google.com/swift-gn.
Bug: 121
Change-Id: If92b49f15e9ebb273feff7c935ca51698c27afa3
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/9180
Commit-Queue: Sylvain Defresne <sdefresne@chromium.org>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/build/gen.py b/build/gen.py
index e7a86ec..9353fb1 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -586,6 +586,9 @@
'src/gn/substitution_pattern.cc',
'src/gn/substitution_type.cc',
'src/gn/substitution_writer.cc',
+ 'src/gn/swift_values.cc',
+ 'src/gn/swift_values_generator.cc',
+ 'src/gn/swift_variables.cc',
'src/gn/switches.cc',
'src/gn/target.cc',
'src/gn/target_generator.cc',
diff --git a/docs/reference.md b/docs/reference.md
index 8fc86fd..168d64e 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -92,6 +92,7 @@
* [args: [string list] Arguments passed to an action.](#var_args)
* [asmflags: [string list] Flags passed to the assembler.](#var_asmflags)
* [assert_no_deps: [label pattern list] Ensure no deps on these targets.](#var_assert_no_deps)
+ * [bridge_header: [string] Path to C/Objective-C compatibility header.](#var_bridge_header)
* [bundle_contents_dir: Expansion of {{bundle_contents_dir}} in create_bundle.](#var_bundle_contents_dir)
* [bundle_deps_filter: [label list] A list of labels that are filtered out.](#var_bundle_deps_filter)
* [bundle_executable_dir: Expansion of {{bundle_executable_dir}} in create_bundle](#var_bundle_executable_dir)
@@ -129,6 +130,7 @@
* [lib_dirs: [directory list] Additional library directories.](#var_lib_dirs)
* [libs: [string list] Additional libraries to link.](#var_libs)
* [metadata: [scope] Metadata of this target.](#var_metadata)
+ * [module_name: [string] The name for the compiled module.](#var_module_name)
* [output_conversion: Data format for generated_file targets.](#var_output_conversion)
* [output_dir: [directory] Directory to put output file in.](#var_output_dir)
* [output_extension: [string] Value to use for the output's file extension.](#var_output_extension)
@@ -148,6 +150,7 @@
* [response_file_contents: [string list] Contents of .rsp file for actions.](#var_response_file_contents)
* [script: [file name] Script file for actions.](#var_script)
* [sources: [file list] Source files for a target.](#var_sources)
+ * [swiftflags: [string list] Flags passed to the swift compiler.](#var_swiftflags)
* [testonly: [boolean] Declares a target must only be used for testing.](#var_testonly)
* [visibility: [label list] A list of labels that can depend on a target.](#var_visibility)
* [walk_keys: [string list] Key(s) for managing the metadata collection walk.](#var_walk_keys)
@@ -1676,7 +1679,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -1870,7 +1873,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -1902,7 +1905,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -1937,7 +1940,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -1971,7 +1974,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -2016,7 +2019,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -2040,7 +2043,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Deps: data_deps, deps, public_deps
Dependent configs: all_dependent_configs, public_configs
General: check_includes, configs, data, friend, inputs, metadata,
@@ -2149,7 +2152,7 @@
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,
libs, precompiled_header, precompiled_source, rustflags,
- rustenv
+ rustenv, swiftflags
Nested configs: configs
```
@@ -3349,10 +3352,12 @@
Compiler tools:
"cc": C compiler
"cxx": C++ compiler
+ "cxx_module": C++ compiler used for Clang .modulemap files
"objc": Objective C compiler
"objcxx": Objective C++ compiler
"rc": Resource compiler (Windows .rc files)
"asm": Assembler
+ "swift": Swift compiler driver
Linker tools:
"alink": Linker for static libraries (archives)
@@ -3497,6 +3502,19 @@
would be:
"-F. -framework UIKit -framework Foo -weak_framework MediaPlayer"
+ swiftmodule_switch [string, optional, link tools only]
+ Valid for: Linker tools except "alink"
+
+ The string will be prependend to the path to the .swiftmodule files
+ that are embedded in the linker output.
+
+ If you specified:
+ swiftmodule_swift = "-Wl,-add_ast_path,"
+ then the "{{swiftmodules}}" expansion for
+ [ "obj/foo/Foo.swiftmodule" ]
+ would be
+ "-Wl,-add_ast_path,obj/foo/Foo.swiftmodule"
+
outputs [list of strings with substitutions]
Valid for: Linker and compiler tools (required)
@@ -3527,6 +3545,17 @@
"{{output_dir}}/{{target_output_name}}.lib",
]
+ partial_outputs [list of strings with substitutions]
+ Valid for: "swift" only
+
+ An array of names for the partial outputs the tool produces. These
+ are relative to the build output directory. The expansion will be
+ evaluated for each file listed in the "sources" of the target.
+
+ This is used to deal with whole module optimization, allowing to
+ list one object file per source file when whole module optimization
+ is disabled.
+
pool [label, optional]
Valid for: all tools (optional)
@@ -3776,6 +3805,13 @@
{{frameworks}} and each item will be preceded by "-framework" or
"-weak_framework".
+ {{swiftmodules}}
+ Swift .swiftmodule files that needs to be embedded into the binary.
+ This is necessary to correctly link with object generated by the
+ Swift compiler (the .swiftmodule file cannot be embedded in object
+ files directly). Those will be prefixed with "swiftmodule_switch"
+ value.
+
The static library ("alink") tool allows {{arflags}} plus the common tool
substitutions.
@@ -3813,6 +3849,21 @@
Expands to the list of flags specified in corresponding
create_bundle target.
+ The Swift tool has multiple input and outputs. It must have exactly one
+ output of .swiftmodule type, but can have one or more object file outputs,
+ in addition to other type of ouputs. The following expansions are available:
+
+ {{module_name}}
+ Expands to the string representing the module name of target under
+ compilation (see "module_name" variable).
+
+ {{module_dirs}}
+ Expands to the list of -I<path> for the target Swift module search
+ path computed from target dependencies.
+
+ {{swiftflags}}
+ Expands to the list of strings representing Swift compiler flags.
+
Rust tools have the notion of a single input and a single output, along
with a set of compiler-specific flags. The following expansions are
available:
@@ -4668,6 +4719,14 @@
]
}
```
+### <a name="var_bridge_header"></a>**bridge_header**: [string] Path to C/Objective-C compatibility header.
+
+```
+ Valid for binary targets that contain Swift sources.
+
+ Path to an header that includes C/Objective-C functions and types that
+ needs to be made available to the Swift module.
+```
### <a name="var_bundle_contents_dir"></a>**bundle_contents_dir**: Expansion of {{bundle_contents_dir}} in
```
create_bundle.
@@ -4778,7 +4837,8 @@
versions of cflags* will be appended on the compiler command line after
"cflags".
- See also "asmflags" for flags for assembly-language files.
+ See also "asmflags" for flags for assembly-language files and "swiftflags"
+ for swift files.
```
#### **Ordering of flags and values**
@@ -4811,7 +4871,8 @@
versions of cflags* will be appended on the compiler command line after
"cflags".
- See also "asmflags" for flags for assembly-language files.
+ See also "asmflags" for flags for assembly-language files and "swiftflags"
+ for swift files.
```
#### **Ordering of flags and values**
@@ -4844,7 +4905,8 @@
versions of cflags* will be appended on the compiler command line after
"cflags".
- See also "asmflags" for flags for assembly-language files.
+ See also "asmflags" for flags for assembly-language files and "swiftflags"
+ for swift files.
```
#### **Ordering of flags and values**
@@ -4877,7 +4939,8 @@
versions of cflags* will be appended on the compiler command line after
"cflags".
- See also "asmflags" for flags for assembly-language files.
+ See also "asmflags" for flags for assembly-language files and "swiftflags"
+ for swift files.
```
#### **Ordering of flags and values**
@@ -4910,7 +4973,8 @@
versions of cflags* will be appended on the compiler command line after
"cflags".
- See also "asmflags" for flags for assembly-language files.
+ See also "asmflags" for flags for assembly-language files and "swiftflags"
+ for swift files.
```
#### **Ordering of flags and values**
@@ -5753,6 +5817,13 @@
}
}
```
+### <a name="var_module_name"></a>**module_name**: [string] The name for the compiled module.
+
+```
+ Valid for binary targets that contain Swift sources.
+
+ If module_name is not set, then this rule will use the target name.
+```
### <a name="var_output_conversion"></a>**output_conversion**: Data format for generated_file targets.
```
@@ -6307,6 +6378,32 @@
copy
The source are the source files to copy.
```
+### <a name="var_swiftflags"></a>**swiftflags**: Flags passed to the swift compiler.
+
+```
+ A list of strings.
+
+ "swiftflags" are passed to any invocation of a tool that takes an .swift
+ file as input.
+```
+
+#### **Ordering of flags and values**
+
+```
+ 1. Those set on the current target (not in a config).
+ 2. Those set on the "configs" on the target in order that the
+ configs appear in the list.
+ 3. Those set on the "all_dependent_configs" on the target in order
+ that the configs appear in the list.
+ 4. Those set on the "public_configs" on the target in order that
+ those configs appear in the list.
+ 5. all_dependent_configs pulled from dependencies, in the order of
+ the "deps" list. This is done recursively. If a config appears
+ more than once, only the first occurence will be used.
+ 6. public_configs pulled from dependencies, in the order of the
+ "deps" list. If a dependency is public, they will be applied
+ recursively.
+```
### <a name="var_testonly"></a>**testonly**: Declares a target must only be used for testing.
```
diff --git a/src/gn/binary_target_generator.cc b/src/gn/binary_target_generator.cc
index 6c085e6..485884e 100644
--- a/src/gn/binary_target_generator.cc
+++ b/src/gn/binary_target_generator.cc
@@ -14,6 +14,7 @@
#include "gn/rust_variables.h"
#include "gn/scope.h"
#include "gn/settings.h"
+#include "gn/swift_values_generator.h"
#include "gn/value_extractors.h"
#include "gn/variables.h"
@@ -73,6 +74,13 @@
return;
}
+ if (target_->source_types_used().SwiftSourceUsed()) {
+ SwiftValuesGenerator swiftgen(target_, scope_, err_);
+ swiftgen.Run();
+ if (err_->has_error())
+ return;
+ }
+
// Config values (compiler flags, etc.) set directly on this target.
ConfigValuesGenerator gen(&target_->config_values(), scope_,
scope_->GetSourceDir(), err_);
@@ -99,9 +107,11 @@
case SourceFile::SOURCE_GO:
case SourceFile::SOURCE_RS:
case SourceFile::SOURCE_RC:
+ case SourceFile::SOURCE_SWIFT:
// These are allowed.
break;
case SourceFile::SOURCE_UNKNOWN:
+ case SourceFile::SOURCE_SWIFTMODULE:
case SourceFile::SOURCE_NUMTYPES:
*err_ =
Err(scope_->GetValue(variables::kSources, true)->list_value()[i],
diff --git a/src/gn/c_substitution_type.cc b/src/gn/c_substitution_type.cc
index b9b7eba..d0c04c8 100644
--- a/src/gn/c_substitution_type.cc
+++ b/src/gn/c_substitution_type.cc
@@ -10,18 +10,21 @@
#include "gn/err.h"
const SubstitutionTypes CSubstitutions = {
- &CSubstitutionAsmFlags, &CSubstitutionCFlags,
- &CSubstitutionCFlagsC, &CSubstitutionCFlagsCc,
- &CSubstitutionCFlagsObjC, &CSubstitutionCFlagsObjCc,
- &CSubstitutionDefines, &CSubstitutionFrameworkDirs,
- &CSubstitutionIncludeDirs,
+ &CSubstitutionAsmFlags, &CSubstitutionCFlags,
+ &CSubstitutionCFlagsC, &CSubstitutionCFlagsCc,
+ &CSubstitutionCFlagsObjC, &CSubstitutionCFlagsObjCc,
+ &CSubstitutionDefines, &CSubstitutionFrameworkDirs,
+ &CSubstitutionIncludeDirs, &CSubstitutionSwiftModules,
- &CSubstitutionLinkerInputs, &CSubstitutionLinkerInputsNewline,
- &CSubstitutionLdFlags, &CSubstitutionLibs,
- &CSubstitutionSoLibs, &CSubstitutionFrameworks,
+ &CSubstitutionLinkerInputs, &CSubstitutionLinkerInputsNewline,
+ &CSubstitutionLdFlags, &CSubstitutionLibs,
+ &CSubstitutionSoLibs, &CSubstitutionFrameworks,
&CSubstitutionRlibs,
&CSubstitutionArFlags,
+
+ &CSubstitutionSwiftModuleName, &CSubstitutionSwiftBridgeHeader,
+ &CSubstitutionSwiftModuleDirs, &CSubstitutionSwiftFlags,
};
// Valid for compiler tools.
@@ -47,10 +50,21 @@
const Substitution CSubstitutionSoLibs = {"{{solibs}}", "solibs"};
const Substitution CSubstitutionRlibs = {"{{rlibs}}", "rlibs"};
const Substitution CSubstitutionFrameworks = {"{{frameworks}}", "frameworks"};
+const Substitution CSubstitutionSwiftModules = {"{{swiftmodules}}",
+ "swiftmodules"};
// Valid for alink only.
const Substitution CSubstitutionArFlags = {"{{arflags}}", "arflags"};
+// Valid for swift only.
+const Substitution CSubstitutionSwiftModuleName = {"{{module_name}}",
+ "module_name"};
+const Substitution CSubstitutionSwiftBridgeHeader = {"{{bridge_header}}",
+ "bridge_header"};
+const Substitution CSubstitutionSwiftModuleDirs = {"{{module_dirs}}",
+ "module_dirs"};
+const Substitution CSubstitutionSwiftFlags = {"{{swiftflags}}", "swiftflags"};
+
bool IsValidCompilerSubstitution(const Substitution* type) {
return IsValidToolSubstitution(type) || IsValidSourceSubstitution(type) ||
type == &SubstitutionSource || type == &CSubstitutionAsmFlags ||
@@ -67,6 +81,22 @@
IsValidSourceSubstitution(type);
}
+bool IsValidSwiftCompilerSubstitution(const Substitution* type) {
+ return IsValidToolSubstitution(type) ||
+ type == &CSubstitutionSwiftModuleName ||
+ type == &CSubstitutionLinkerInputs ||
+ type == &CSubstitutionIncludeDirs ||
+ type == &CSubstitutionSwiftBridgeHeader ||
+ type == &CSubstitutionSwiftModuleDirs ||
+ type == &CSubstitutionSwiftFlags || type == &CSubstitutionDefines;
+}
+
+bool IsValidSwiftCompilerOutputsSubstitution(const Substitution* type) {
+ return (IsValidSwiftCompilerSubstitution(type) &&
+ type != &SubstitutionOutput) ||
+ IsValidSourceSubstitution(type);
+}
+
bool IsValidLinkerSubstitution(const Substitution* type) {
return IsValidToolSubstitution(type) || type == &SubstitutionOutputDir ||
type == &SubstitutionOutputExtension ||
@@ -74,7 +104,7 @@
type == &CSubstitutionLinkerInputsNewline ||
type == &CSubstitutionLdFlags || type == &CSubstitutionLibs ||
type == &CSubstitutionSoLibs || type == &CSubstitutionFrameworks ||
- type == &CSubstitutionRlibs;
+ type == &CSubstitutionRlibs || type == &CSubstitutionSwiftModules;
}
bool IsValidLinkerOutputsSubstitution(const Substitution* type) {
diff --git a/src/gn/c_substitution_type.h b/src/gn/c_substitution_type.h
index d4ba606..63eb627 100644
--- a/src/gn/c_substitution_type.h
+++ b/src/gn/c_substitution_type.h
@@ -32,13 +32,22 @@
extern const Substitution CSubstitutionSoLibs;
extern const Substitution CSubstitutionFrameworks;
extern const Substitution CSubstitutionRlibs;
+extern const Substitution CSubstitutionSwiftModules;
// Valid for alink only.
extern const Substitution CSubstitutionArFlags;
+// Valid for swift only.
+extern const Substitution CSubstitutionSwiftModuleName;
+extern const Substitution CSubstitutionSwiftBridgeHeader;
+extern const Substitution CSubstitutionSwiftModuleDirs;
+extern const Substitution CSubstitutionSwiftFlags;
+
// Both compiler and linker tools.
bool IsValidCompilerSubstitution(const Substitution* type);
bool IsValidCompilerOutputsSubstitution(const Substitution* type);
+bool IsValidSwiftCompilerSubstitution(const Substitution* type);
+bool IsValidSwiftCompilerOutputsSubstitution(const Substitution* type);
bool IsValidLinkerSubstitution(const Substitution* type);
bool IsValidLinkerOutputsSubstitution(const Substitution* type);
bool IsValidALinkSubstitution(const Substitution* type);
diff --git a/src/gn/c_tool.cc b/src/gn/c_tool.cc
index dc391d1..767b324 100644
--- a/src/gn/c_tool.cc
+++ b/src/gn/c_tool.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "gn/c_tool.h"
+
+#include "base/strings/stringprintf.h"
#include "gn/c_substitution_type.h"
#include "gn/target.h"
@@ -13,6 +15,7 @@
const char* CTool::kCToolObjCxx = "objcxx";
const char* CTool::kCToolRc = "rc";
const char* CTool::kCToolAsm = "asm";
+const char* CTool::kCToolSwift = "swift";
const char* CTool::kCToolAlink = "alink";
const char* CTool::kCToolSolink = "solink";
const char* CTool::kCToolSolinkModule = "solink_module";
@@ -41,8 +44,9 @@
bool CTool::ValidateName(const char* name) const {
return name == kCToolCc || name == kCToolCxx || name == kCToolCxxModule ||
name == kCToolObjC || name == kCToolObjCxx || name == kCToolRc ||
- name == kCToolAsm || name == kCToolAlink || name == kCToolSolink ||
- name == kCToolSolinkModule || name == kCToolLink;
+ name == kCToolSwift || name == kCToolAsm || name == kCToolAlink ||
+ name == kCToolSolink || name == kCToolSolinkModule ||
+ name == kCToolLink;
}
void CTool::SetComplete() {
@@ -141,6 +145,7 @@
bool CTool::ReadOutputsPatternList(Scope* scope,
const char* var,
+ bool required,
SubstitutionList* field,
Err* err) {
DCHECK(!complete_);
@@ -155,8 +160,10 @@
return false;
// Validate the right kinds of patterns are used.
- if (list.list().empty()) {
- *err = Err(defined_from(), "\"outputs\" must be specified for this tool.");
+ if (list.list().empty() && required) {
+ *err =
+ Err(defined_from(),
+ base::StringPrintf("\"%s\" must be specified for this tool.", var));
return false;
}
@@ -180,7 +187,8 @@
}
// All C tools should have outputs.
- if (!ReadOutputsPatternList(scope, "outputs", &outputs_, err)) {
+ if (!ReadOutputsPatternList(scope, "outputs", /*required=*/true, &outputs_,
+ err)) {
return false;
}
@@ -192,10 +200,19 @@
!ReadString(scope, "lib_switch", &lib_switch_, err) ||
!ReadString(scope, "lib_dir_switch", &lib_dir_switch_, err) ||
!ReadPattern(scope, "link_output", &link_output_, err) ||
+ !ReadString(scope, "swiftmodule_switch", &swiftmodule_switch_, err) ||
!ReadPattern(scope, "depend_output", &depend_output_, err)) {
return false;
}
+ // Swift tool can optionally specify partial_outputs.
+ if (name_ == kCToolSwift) {
+ if (!ReadOutputsPatternList(scope, "partial_outputs", /*required=*/false,
+ &partial_outputs_, err)) {
+ return false;
+ }
+ }
+
// Validate link_output and depend_output.
if (!ValidateLinkAndDependOutput(link_output(), "link_output", err)) {
return false;
@@ -222,6 +239,8 @@
name_ == kCToolObjC || name_ == kCToolObjCxx || name_ == kCToolRc ||
name_ == kCToolAsm)
return IsValidCompilerSubstitution(sub_type);
+ if (name_ == kCToolSwift)
+ return IsValidSwiftCompilerSubstitution(sub_type);
else if (name_ == kCToolAlink)
return IsValidALinkSubstitution(sub_type);
else if (name_ == kCToolSolink || name_ == kCToolSolinkModule ||
@@ -236,6 +255,8 @@
name_ == kCToolObjC || name_ == kCToolObjCxx || name_ == kCToolRc ||
name_ == kCToolAsm)
return IsValidCompilerOutputsSubstitution(sub_type);
+ if (name_ == kCToolSwift)
+ return IsValidSwiftCompilerOutputsSubstitution(sub_type);
// ALink uses the standard output file patterns as other linker tools.
else if (name_ == kCToolAlink || name_ == kCToolSolink ||
name_ == kCToolSolinkModule || name_ == kCToolLink)
diff --git a/src/gn/c_tool.h b/src/gn/c_tool.h
index 01b2431..fe32e53 100644
--- a/src/gn/c_tool.h
+++ b/src/gn/c_tool.h
@@ -27,6 +27,7 @@
static const char* kCToolObjCxx;
static const char* kCToolRc;
static const char* kCToolAsm;
+ static const char* kCToolSwift;
// C linker tools
static const char* kCToolAlink;
@@ -108,6 +109,7 @@
Err* err);
bool ReadOutputsPatternList(Scope* scope,
const char* var,
+ bool required,
SubstitutionList* field,
Err* err);
bool ReadPrecompiledHeaderType(Scope* scope, Err* err);
diff --git a/src/gn/command_desc.cc b/src/gn/command_desc.cc
index cdb2e74..e36cf0b 100644
--- a/src/gn/command_desc.cc
+++ b/src/gn/command_desc.cc
@@ -16,12 +16,13 @@
#include "gn/commands.h"
#include "gn/config.h"
#include "gn/desc_builder.h"
+#include "gn/rust_variables.h"
#include "gn/setup.h"
#include "gn/standard_out.h"
+#include "gn/swift_variables.h"
#include "gn/switches.h"
#include "gn/target.h"
#include "gn/variables.h"
-#include "gn/rust_variables.h"
namespace commands {
@@ -304,6 +305,8 @@
{variables::kWriteOutputConversion, DefaultHandler},
{variables::kRustCrateName, DefaultHandler},
{variables::kRustCrateRoot, DefaultHandler},
+ {variables::kSwiftModuleName, DefaultHandler},
+ {variables::kSwiftBridgeHeader, DefaultHandler},
{"runtime_deps", DefaultHandler}};
}
@@ -354,6 +357,7 @@
// Entries with DefaultHandler are present to enforce order
HandleProperty("type", handler_map, v, dict);
HandleProperty("toolchain", handler_map, v, dict);
+ HandleProperty(variables::kSwiftModuleName, handler_map, v, dict);
HandleProperty(variables::kRustCrateName, handler_map, v, dict);
HandleProperty(variables::kRustCrateRoot, handler_map, v, dict);
HandleProperty(variables::kVisibility, handler_map, v, dict);
@@ -362,6 +366,7 @@
HandleProperty(variables::kCheckIncludes, handler_map, v, dict);
HandleProperty(variables::kAllowCircularIncludesFrom, handler_map, v, dict);
HandleProperty(variables::kSources, handler_map, v, dict);
+ HandleProperty(variables::kSwiftBridgeHeader, handler_map, v, dict);
HandleProperty(variables::kPublic, handler_map, v, dict);
HandleProperty(variables::kInputs, handler_map, v, dict);
HandleProperty(variables::kConfigs, handler_map, v, dict);
@@ -379,6 +384,7 @@
HandleProperty(variables::kCflagsCC, handler_map, v, dict);
HandleProperty(variables::kCflagsObjC, handler_map, v, dict);
HandleProperty(variables::kCflagsObjCC, handler_map, v, dict);
+ HandleProperty(variables::kSwiftflags, handler_map, v, dict);
HandleProperty(variables::kDefines, handler_map, v, dict);
HandleProperty(variables::kFrameworkDirs, handler_map, v, dict);
HandleProperty(variables::kFrameworks, handler_map, v, dict);
@@ -444,6 +450,7 @@
HandleProperty(variables::kCflagsCC, handler_map, v, dict);
HandleProperty(variables::kCflagsObjC, handler_map, v, dict);
HandleProperty(variables::kCflagsObjCC, handler_map, v, dict);
+ HandleProperty(variables::kSwiftflags, handler_map, v, dict);
HandleProperty(variables::kDefines, handler_map, v, dict);
HandleProperty(variables::kFrameworkDirs, handler_map, v, dict);
HandleProperty(variables::kFrameworks, handler_map, v, dict);
diff --git a/src/gn/config_values.cc b/src/gn/config_values.cc
index ba5ddf7..9bddf99 100644
--- a/src/gn/config_values.cc
+++ b/src/gn/config_values.cc
@@ -39,6 +39,7 @@
VectorAppend(&libs_, append.libs_);
VectorAppend(&rustflags_, append.rustflags_);
VectorAppend(&rustenv_, append.rustenv_);
+ VectorAppend(&swiftflags_, append.swiftflags_);
// Only append precompiled header if there isn't one. It might be nice to
// throw an error if there are conflicting precompiled headers, but that
diff --git a/src/gn/config_values.h b/src/gn/config_values.h
index ef57b26..6361e78 100644
--- a/src/gn/config_values.h
+++ b/src/gn/config_values.h
@@ -50,6 +50,7 @@
DIR_VALUES_ACCESSOR(lib_dirs)
STRING_VALUES_ACCESSOR(rustflags)
STRING_VALUES_ACCESSOR(rustenv)
+ STRING_VALUES_ACCESSOR(swiftflags)
// =================================================================
// IMPORTANT: If you add a new one, be sure to update AppendValues()
// and command_desc.cc.
@@ -96,6 +97,7 @@
std::vector<LibFile> libs_;
std::vector<std::string> rustflags_;
std::vector<std::string> rustenv_;
+ std::vector<std::string> swiftflags_;
std::vector<std::pair<std::string, LibFile>> externs_;
// If you add a new one, be sure to update AppendValues().
diff --git a/src/gn/config_values_generator.cc b/src/gn/config_values_generator.cc
index c8070d2..fac03d7 100644
--- a/src/gn/config_values_generator.cc
+++ b/src/gn/config_values_generator.cc
@@ -106,6 +106,7 @@
FILL_DIR_CONFIG_VALUE(lib_dirs)
FILL_STRING_CONFIG_VALUE(rustflags)
FILL_STRING_CONFIG_VALUE(rustenv)
+ FILL_STRING_CONFIG_VALUE(swiftflags)
#undef FILL_STRING_CONFIG_VALUE
#undef FILL_DIR_CONFIG_VALUE
diff --git a/src/gn/config_values_generator.h b/src/gn/config_values_generator.h
index b9740d1..b7b008c 100644
--- a/src/gn/config_values_generator.h
+++ b/src/gn/config_values_generator.h
@@ -41,6 +41,6 @@
" Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,\n" \
" asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,\n" \
" libs, precompiled_header, precompiled_source, rustflags,\n" \
- " rustenv\n"
+ " rustenv, swiftflags\n"
#endif // TOOLS_GN_CONFIG_VALUES_GENERATOR_H_
diff --git a/src/gn/desc_builder.cc b/src/gn/desc_builder.cc
index 3865ac0..d8639b1 100644
--- a/src/gn/desc_builder.cc
+++ b/src/gn/desc_builder.cc
@@ -20,6 +20,7 @@
#include "gn/settings.h"
#include "gn/standard_out.h"
#include "gn/substitution_writer.h"
+#include "gn/swift_variables.h"
#include "gn/variables.h"
// Example structure of Value for single target
@@ -276,6 +277,7 @@
CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir)
CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile)
+ CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string)
#undef CONFIG_VALUE_ARRAY_HANDLER
@@ -340,6 +342,18 @@
}
}
+ if (target_->source_types_used().SwiftSourceUsed()) {
+ if (what(variables::kSwiftBridgeHeader)) {
+ res->SetWithoutPathExpansion(
+ variables::kSwiftBridgeHeader,
+ RenderValue(target_->swift_values().bridge_header()));
+ }
+ if (what(variables::kSwiftModuleName)) {
+ res->SetKey(variables::kSwiftModuleName,
+ base::Value(target_->swift_values().module_name()));
+ }
+ }
+
// General target meta variables.
if (what(variables::kMetadata)) {
@@ -491,6 +505,7 @@
CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile)
CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
+ CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string)
#undef CONFIG_VALUE_ARRAY_HANDLER
// Libs and lib_dirs are handled specially below.
diff --git a/src/gn/function_toolchain.cc b/src/gn/function_toolchain.cc
index a6642d1..1288511 100644
--- a/src/gn/function_toolchain.cc
+++ b/src/gn/function_toolchain.cc
@@ -289,6 +289,7 @@
"objcxx": Objective C++ compiler
"rc": Resource compiler (Windows .rc files)
"asm": Assembler
+ "swift": Swift compiler driver
Linker tools:
"alink": Linker for static libraries (archives)
@@ -431,6 +432,19 @@
would be:
"-F. -framework UIKit -framework Foo -weak_framework MediaPlayer"
+ swiftmodule_switch [string, optional, link tools only]
+ Valid for: Linker tools except "alink"
+
+ The string will be prependend to the path to the .swiftmodule files
+ that are embedded in the linker output.
+
+ If you specified:
+ swiftmodule_swift = "-Wl,-add_ast_path,"
+ then the "{{swiftmodules}}" expansion for
+ [ "obj/foo/Foo.swiftmodule" ]
+ would be
+ "-Wl,-add_ast_path,obj/foo/Foo.swiftmodule"
+
outputs [list of strings with substitutions]
Valid for: Linker and compiler tools (required)
@@ -461,6 +475,17 @@
"{{output_dir}}/{{target_output_name}}.lib",
]
+ partial_outputs [list of strings with substitutions]
+ Valid for: "swift" only
+
+ An array of names for the partial outputs the tool produces. These
+ are relative to the build output directory. The expansion will be
+ evaluated for each file listed in the "sources" of the target.
+
+ This is used to deal with whole module optimization, allowing to
+ list one object file per source file when whole module optimization
+ is disabled.
+
pool [label, optional]
Valid for: all tools (optional)
@@ -709,6 +734,13 @@
{{frameworks}} and each item will be preceded by "-framework" or
"-weak_framework".
+ {{swiftmodules}}
+ Swift .swiftmodule files that needs to be embedded into the binary.
+ This is necessary to correctly link with object generated by the
+ Swift compiler (the .swiftmodule file cannot be embedded in object
+ files directly). Those will be prefixed with "swiftmodule_switch"
+ value.
+
)" // String break to prevent overflowing the 16K max VC string length.
R"( The static library ("alink") tool allows {{arflags}} plus the common tool
substitutions.
@@ -747,6 +779,21 @@
Expands to the list of flags specified in corresponding
create_bundle target.
+ The Swift tool has multiple input and outputs. It must have exactly one
+ output of .swiftmodule type, but can have one or more object file outputs,
+ in addition to other type of ouputs. The following expansions are available:
+
+ {{module_name}}
+ Expands to the string representing the module name of target under
+ compilation (see "module_name" variable).
+
+ {{module_dirs}}
+ Expands to the list of -I<path> for the target Swift module search
+ path computed from target dependencies.
+
+ {{swiftflags}}
+ Expands to the list of strings representing Swift compiler flags.
+
Rust tools have the notion of a single input and a single output, along
with a set of compiler-specific flags. The following expansions are
available:
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc
index 098a595..08e8c93 100644
--- a/src/gn/ninja_binary_target_writer.cc
+++ b/src/gn/ninja_binary_target_writer.cc
@@ -156,6 +156,9 @@
// don't link at all.
bool can_link_libs = target_->IsFinal();
+ if (can_link_libs && dep->swift_values().builds_module())
+ classified_deps->swiftmodule_deps.push_back(dep);
+
if (dep->output_type() == Target::SOURCE_SET ||
// If a complete static library depends on an incomplete static library,
// manually link in the object files of the dependent library as if it
@@ -209,6 +212,25 @@
obj_files->push_back(tool_outputs[0]);
}
+ // Swift files may generate one object file per module or one per source file
+ // depending on how the compiler is invoked (whole module optimization).
+ if (source_set->source_types_used().SwiftSourceUsed()) {
+ const Tool* tool = source_set->toolchain()->GetToolForSourceTypeAsC(
+ SourceFile::SOURCE_SWIFT);
+
+ std::vector<OutputFile> outputs;
+ SubstitutionWriter::ApplyListToLinkerAsOutputFile(
+ source_set, tool, tool->outputs(), &outputs);
+
+ for (const OutputFile& output : outputs) {
+ SourceFile output_as_source =
+ output.AsSourceFile(source_set->settings()->build_settings());
+ if (output_as_source.type() == SourceFile::SOURCE_O) {
+ obj_files->push_back(output);
+ }
+ }
+ }
+
// Add MSVC precompiled header object files. GCC .gch files are not object
// files so they are omitted.
if (source_set->config_values().has_precompiled_headers()) {
@@ -348,3 +370,19 @@
weak_writer(all_weak_frameworks[i], out);
}
}
+
+void NinjaBinaryTargetWriter::WriteSwiftModules(
+ std::ostream& out,
+ const Tool* tool,
+ const std::vector<OutputFile>& swiftmodules) {
+ // Since we're passing these on the command line to the linker and not
+ // to Ninja, we need to do shell escaping.
+ PathOutput swiftmodule_path_output(
+ path_output_.current_dir(), settings_->build_settings()->root_path_utf8(),
+ ESCAPE_NINJA_COMMAND);
+
+ for (const OutputFile& swiftmodule : swiftmodules) {
+ out << " " << tool->swiftmodule_switch();
+ swiftmodule_path_output.WriteFile(out, swiftmodule);
+ }
+}
diff --git a/src/gn/ninja_binary_target_writer.h b/src/gn/ninja_binary_target_writer.h
index 142ca9e..76a8a4e 100644
--- a/src/gn/ninja_binary_target_writer.h
+++ b/src/gn/ninja_binary_target_writer.h
@@ -30,6 +30,7 @@
UniqueVector<const Target*> linkable_deps;
UniqueVector<const Target*> non_linkable_deps;
UniqueVector<const Target*> framework_deps;
+ UniqueVector<const Target*> swiftmodule_deps;
};
// Writes to the output stream a stamp rule for inputs, and
@@ -70,6 +71,9 @@
const SourceFile* optional_def_file);
void WriteLibs(std::ostream& out, const Tool* tool);
void WriteFrameworks(std::ostream& out, const Tool* tool);
+ void WriteSwiftModules(std::ostream& out,
+ const Tool* tool,
+ const std::vector<OutputFile>& swiftmodules);
void AddSourceSetFiles(const Target* source_set,
UniqueVector<OutputFile>* obj_files) const;
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index 80448a8..62edd4f 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -126,8 +126,12 @@
// object file list.
std::vector<OutputFile> obj_files;
std::vector<SourceFile> other_files;
- WriteSources(*pch_files, input_deps, order_only_deps, &obj_files,
- &other_files);
+ if (!target_->source_types_used().SwiftSourceUsed()) {
+ WriteSources(*pch_files, input_deps, order_only_deps, &obj_files,
+ &other_files);
+ } else {
+ WriteSwiftSources(input_deps, order_only_deps, &obj_files);
+ }
// Link all MSVC pch object files. The vector will be empty on GCC toolchains.
obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end());
@@ -225,6 +229,44 @@
CTool::kCToolObjCxx, &ConfigValues::cflags_objcc, opts,
path_output_, out_);
}
+ if (target_->source_types_used().SwiftSourceUsed()) {
+ if (subst.used.count(&CSubstitutionSwiftModuleName)) {
+ out_ << CSubstitutionSwiftModuleName.ninja_name << " = ";
+ EscapeStringToStream(out_, target_->swift_values().module_name(), opts);
+ out_ << std::endl;
+ }
+
+ if (subst.used.count(&CSubstitutionSwiftBridgeHeader)) {
+ out_ << CSubstitutionSwiftBridgeHeader.ninja_name << " = ";
+ if (!target_->swift_values().bridge_header().is_null()) {
+ path_output_.WriteFile(out_, target_->swift_values().bridge_header());
+ } else {
+ out_ << R"("")";
+ }
+ out_ << std::endl;
+ }
+
+ if (subst.used.count(&CSubstitutionSwiftModuleDirs)) {
+ // Uniquify the list of swiftmodule dirs (in case multiple swiftmodules
+ // are generated in the same directory).
+ UniqueVector<SourceDir> swiftmodule_dirs;
+ for (const Target* dep : target_->swift_values().modules())
+ swiftmodule_dirs.push_back(dep->swift_values().module_output_dir());
+
+ out_ << CSubstitutionSwiftModuleDirs.ninja_name << " =";
+ PathOutput swiftmodule_path_output(
+ path_output_.current_dir(),
+ settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND);
+ IncludeWriter swiftmodule_path_writer(swiftmodule_path_output);
+ for (const SourceDir& swiftmodule_dir : swiftmodule_dirs) {
+ swiftmodule_path_writer(swiftmodule_dir, out_);
+ }
+ out_ << std::endl;
+ }
+
+ WriteOneFlag(target_, &CSubstitutionSwiftFlags, false, CTool::kCToolSwift,
+ &ConfigValues::swiftflags, opts, path_output_, out_);
+ }
WriteSharedVars(subst);
}
@@ -387,11 +429,14 @@
const std::vector<OutputFile>& order_only_deps,
std::vector<OutputFile>* object_files,
std::vector<SourceFile>* other_files) {
+ DCHECK(!target_->source_types_used().SwiftSourceUsed());
object_files->reserve(object_files->size() + target_->sources().size());
std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop.
std::vector<OutputFile> deps;
for (const auto& source : target_->sources()) {
+ DCHECK_NE(source.type(), SourceFile::SOURCE_SWIFT);
+
// Clear the vector but maintain the max capacity to prevent reallocations.
deps.resize(0);
const char* tool_name = Tool::kToolNone;
@@ -441,6 +486,89 @@
// output, but we'll only link to the first output.
object_files->push_back(tool_outputs[0]);
}
+
+ out_ << std::endl;
+}
+
+void NinjaCBinaryTargetWriter::WriteSwiftSources(
+ const std::vector<OutputFile>& input_deps,
+ const std::vector<OutputFile>& order_only_deps,
+ std::vector<OutputFile>* object_files) {
+ DCHECK(target_->source_types_used().SwiftSourceUsed());
+ object_files->reserve(object_files->size() + target_->sources().size());
+
+ // If the target contains .swift source files, they needs to be compiled as
+ // a single unit but still can produce more than one object file (if the
+ // whole module optimization is disabled).
+ if (target_->source_types_used().SwiftSourceUsed()) {
+ const Tool* tool =
+ target_->toolchain()->GetToolForSourceType(SourceFile::SOURCE_SWIFT);
+
+ const OutputFile swiftmodule_output_file =
+ target_->swift_values().module_output_file();
+
+ std::vector<OutputFile> additional_outputs;
+ SubstitutionWriter::ApplyListToLinkerAsOutputFile(
+ target_, tool, tool->outputs(), &additional_outputs);
+
+ additional_outputs.erase(
+ std::remove(additional_outputs.begin(), additional_outputs.end(),
+ swiftmodule_output_file),
+ additional_outputs.end());
+
+ for (const OutputFile& output : additional_outputs) {
+ const SourceFile output_as_source =
+ output.AsSourceFile(target_->settings()->build_settings());
+
+ if (output_as_source.type() == SourceFile::SOURCE_O) {
+ object_files->push_back(output);
+ }
+ }
+
+ const SubstitutionList& partial_outputs_subst = tool->partial_outputs();
+ if (!partial_outputs_subst.list().empty()) {
+ // Avoid re-allocation during loop.
+ std::vector<OutputFile> partial_outputs;
+ for (const auto& source : target_->sources()) {
+ if (source.type() != SourceFile::SOURCE_SWIFT)
+ continue;
+
+ partial_outputs.resize(0);
+ SubstitutionWriter::ApplyListToCompilerAsOutputFile(
+ target_, source, partial_outputs_subst, &partial_outputs);
+
+ for (const OutputFile& output : partial_outputs) {
+ additional_outputs.push_back(output);
+ SourceFile output_as_source =
+ output.AsSourceFile(target_->settings()->build_settings());
+ if (output_as_source.type() == SourceFile::SOURCE_O) {
+ object_files->push_back(output);
+ }
+ }
+ }
+ }
+
+ UniqueVector<OutputFile> swift_order_only_deps;
+ swift_order_only_deps.reserve(order_only_deps.size());
+ swift_order_only_deps.Append(order_only_deps.begin(),
+ order_only_deps.end());
+
+ for (const Target* swiftmodule : target_->swift_values().modules())
+ swift_order_only_deps.push_back(swiftmodule->dependency_output_file());
+
+ WriteCompilerBuildLine(target_->sources(), input_deps,
+ swift_order_only_deps.vector(), tool->name(),
+ {swiftmodule_output_file});
+
+ if (!additional_outputs.empty()) {
+ out_ << std::endl;
+ WriteCompilerBuildLine(
+ {swiftmodule_output_file.AsSourceFile(settings_->build_settings())},
+ input_deps, swift_order_only_deps.vector(),
+ GeneralTool::kGeneralToolStamp, additional_outputs);
+ }
+ }
+
out_ << std::endl;
}
@@ -538,6 +666,19 @@
}
}
+ // Swift modules from dependencies (and possibly self).
+ std::vector<OutputFile> swiftmodules;
+ if (target_->IsFinal()) {
+ for (const Target* dep : classified_deps.swiftmodule_deps) {
+ swiftmodules.push_back(dep->swift_values().module_output_file());
+ implicit_deps.push_back(dep->swift_values().module_output_file());
+ }
+ if (target_->swift_values().builds_module()) {
+ swiftmodules.push_back(target_->swift_values().module_output_file());
+ implicit_deps.push_back(target_->swift_values().module_output_file());
+ }
+ }
+
// Append implicit dependencies collected above.
if (!implicit_deps.empty()) {
out_ << " |";
@@ -575,6 +716,9 @@
out_ << " frameworks =";
WriteFrameworks(out_, tool_);
out_ << std::endl;
+ out_ << " swiftmodules =";
+ WriteSwiftModules(out_, tool_, swiftmodules);
+ out_ << std::endl;
} else if (target_->output_type() == Target::STATIC_LIBRARY) {
out_ << " arflags =";
RecursiveTargetConfigStringsToStream(target_, &ConfigValues::arflags,
diff --git a/src/gn/ninja_c_binary_target_writer.h b/src/gn/ninja_c_binary_target_writer.h
index 1608af1..695c400 100644
--- a/src/gn/ninja_c_binary_target_writer.h
+++ b/src/gn/ninja_c_binary_target_writer.h
@@ -73,6 +73,9 @@
const std::vector<OutputFile>& order_only_deps,
std::vector<OutputFile>* object_files,
std::vector<SourceFile>* other_files);
+ void WriteSwiftSources(const std::vector<OutputFile>& input_deps,
+ const std::vector<OutputFile>& order_only_deps,
+ std::vector<OutputFile>* object_files);
void WriteLinkerStuff(const std::vector<OutputFile>& object_files,
const std::vector<SourceFile>& other_files,
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc
index fbd6ff4..f650e44 100644
--- a/src/gn/ninja_c_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -58,7 +58,7 @@
"build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
"obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
// A shared library that depends on the source set.
@@ -90,10 +90,11 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
// A static library that depends on the source set (should not link it).
@@ -123,7 +124,7 @@
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
// Make the static library 'complete', which means it should be linked.
@@ -151,7 +152,7 @@
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
}
@@ -209,7 +210,7 @@
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
TEST_F(NinjaCBinaryTargetWriterTest, CompleteStaticLibrary) {
@@ -256,7 +257,7 @@
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
// Make the dependent static library complete.
@@ -285,7 +286,7 @@
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
}
@@ -340,11 +341,12 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so.6\n"
" output_dir = foo\n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
TEST_F(NinjaCBinaryTargetWriterTest, NoHardDepsToNoPublicHeaderTarget) {
@@ -432,6 +434,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = foo\n";
@@ -470,6 +473,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = foo\n";
@@ -507,11 +511,12 @@
" ldflags = -L../../foo/bar\n"
" libs = ../../foo/lib1.a -lfoo\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
// Tests frameworks are applied.
@@ -562,11 +567,12 @@
" libs =\n"
" frameworks = -framework System -framework Bar "
"-weak_framework Whizbang\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
TEST_F(NinjaCBinaryTargetWriterTest, EmptyOutputExtension) {
@@ -608,11 +614,12 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
TEST_F(NinjaCBinaryTargetWriterTest, SourceSetDataDeps) {
@@ -693,6 +700,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = \n";
EXPECT_EQ(final_expected, final_out.str());
@@ -730,6 +738,7 @@
" ldflags = /DEF:../../foo/bar.def\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = \n";
EXPECT_EQ(expected, out.str());
@@ -766,6 +775,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = \n";
EXPECT_EQ(loadable_expected, out.str());
@@ -800,6 +810,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = \n";
EXPECT_EQ(final_expected, final_out.str());
@@ -1157,6 +1168,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = .so\n"
" output_dir = \n";
@@ -1297,6 +1309,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = \n";
@@ -1409,6 +1422,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = \n"
" rlibs = obj/quux/lib4.rlib obj/qux/lib2.rlib\n";
@@ -1470,6 +1484,7 @@
" ldflags =\n"
" libs =\n"
" frameworks =\n"
+ " swiftmodules =\n"
" output_extension = \n"
" output_dir = \n";
@@ -1511,5 +1526,167 @@
" output_extension = \n"
" output_dir = \n";
std::string out_str = out.str();
- EXPECT_EQ(expected, out_str);
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
+// Test linking of targets containing Swift modules.
+TEST_F(NinjaCBinaryTargetWriterTest, SwiftModule) {
+ Err err;
+ TestWithScope setup;
+
+ // A single Swift module.
+ Target foo_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
+ foo_target.set_output_type(Target::SOURCE_SET);
+ foo_target.visibility().SetPublic();
+ foo_target.sources().push_back(SourceFile("//foo/file1.swift"));
+ foo_target.sources().push_back(SourceFile("//foo/file2.swift"));
+ foo_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
+ foo_target.swift_values().module_name() = "Foo";
+ foo_target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(foo_target.OnResolved(&err));
+
+ {
+ std::ostringstream out;
+ NinjaCBinaryTargetWriter writer(&foo_target, out);
+ writer.Run();
+
+ const char expected[] =
+ "defines =\n"
+ "include_dirs =\n"
+ "module_name = Foo\n"
+ "module_dirs =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/foo\n"
+ "target_output_name = foo\n"
+ "\n"
+ "build obj/foo/Foo.swiftmodule: swift"
+ " ../../foo/file1.swift ../../foo/file2.swift\n"
+ "\n"
+ "build obj/foo/file1.o obj/foo/file2.o: stamp obj/foo/Foo.swiftmodule\n"
+ "\n"
+ "build obj/foo/foo.stamp: stamp"
+ " obj/foo/file1.o obj/foo/file2.o\n";
+
+ const std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+
+ // Swift module_dirs correctly set if dependency between Swift modules.
+ {
+ Target bar_target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
+ bar_target.set_output_type(Target::SOURCE_SET);
+ bar_target.visibility().SetPublic();
+ bar_target.sources().push_back(SourceFile("//bar/bar.swift"));
+ bar_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
+ bar_target.swift_values().module_name() = "Bar";
+ bar_target.private_deps().push_back(LabelTargetPair(&foo_target));
+ bar_target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(bar_target.OnResolved(&err));
+
+ std::ostringstream out;
+ NinjaCBinaryTargetWriter writer(&bar_target, out);
+ writer.Run();
+
+ const char expected[] =
+ "defines =\n"
+ "include_dirs =\n"
+ "module_name = Bar\n"
+ "module_dirs = -Iobj/foo\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/bar\n"
+ "target_output_name = bar\n"
+ "\n"
+ "build obj/bar/Bar.swiftmodule: swift ../../bar/bar.swift"
+ " || obj/foo/foo.stamp\n"
+ "\n"
+ "build obj/bar/bar.o: stamp obj/bar/Bar.swiftmodule"
+ " || obj/foo/foo.stamp\n"
+ "\n"
+ "build obj/bar/bar.stamp: stamp obj/bar/bar.o "
+ "|| obj/foo/foo.stamp\n";
+
+ const std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+
+ // Swift module_dirs correctly set if dependency between Swift modules,
+ // even if the dependency is indirect (via public_deps).
+ {
+ Target group(setup.settings(), Label(SourceDir("//bar/"), "group"));
+ group.set_output_type(Target::GROUP);
+ group.visibility().SetPublic();
+ group.public_deps().push_back(LabelTargetPair(&foo_target));
+ group.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(group.OnResolved(&err));
+
+ Target bar_target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
+ bar_target.set_output_type(Target::SOURCE_SET);
+ bar_target.visibility().SetPublic();
+ bar_target.sources().push_back(SourceFile("//bar/bar.swift"));
+ bar_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
+ bar_target.swift_values().module_name() = "Bar";
+ bar_target.private_deps().push_back(LabelTargetPair(&group));
+ bar_target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(bar_target.OnResolved(&err));
+
+ std::ostringstream out;
+ NinjaCBinaryTargetWriter writer(&bar_target, out);
+ writer.Run();
+
+ const char expected[] =
+ "defines =\n"
+ "include_dirs =\n"
+ "module_name = Bar\n"
+ "module_dirs = -Iobj/foo\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/bar\n"
+ "target_output_name = bar\n"
+ "\n"
+ "build obj/bar/Bar.swiftmodule: swift ../../bar/bar.swift"
+ " || obj/foo/foo.stamp\n"
+ "\n"
+ "build obj/bar/bar.o: stamp obj/bar/Bar.swiftmodule"
+ " || obj/foo/foo.stamp\n"
+ "\n"
+ "build obj/bar/bar.stamp: stamp obj/bar/bar.o "
+ "|| obj/bar/group.stamp obj/foo/foo.stamp\n";
+
+ const std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+
+ // C target links with module.
+ {
+ Target bar_target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
+ bar_target.set_output_type(Target::EXECUTABLE);
+ bar_target.visibility().SetPublic();
+ bar_target.private_deps().push_back(LabelTargetPair(&foo_target));
+ bar_target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(bar_target.OnResolved(&err));
+
+ std::ostringstream out;
+ NinjaCBinaryTargetWriter writer(&bar_target, out);
+ writer.Run();
+
+ const char expected[] =
+ "defines =\n"
+ "include_dirs =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/bar\n"
+ "target_output_name = bar\n"
+ "\n"
+ "\n"
+ "build ./bar: link obj/foo/file1.o obj/foo/file2.o "
+ "| obj/foo/Foo.swiftmodule "
+ "|| obj/foo/foo.stamp\n"
+ " ldflags =\n"
+ " libs =\n"
+ " frameworks =\n"
+ " swiftmodules = obj/foo/Foo.swiftmodule\n"
+ " output_extension = \n"
+ " output_dir = \n";
+
+ const std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
}
diff --git a/src/gn/ninja_toolchain_writer.cc b/src/gn/ninja_toolchain_writer.cc
index 3793ab0..7be7719 100644
--- a/src/gn/ninja_toolchain_writer.cc
+++ b/src/gn/ninja_toolchain_writer.cc
@@ -83,7 +83,8 @@
EscapeOptions options;
options.mode = ESCAPE_NINJA_PREFORMATTED_COMMAND;
- WriteCommandRulePattern("command", tool->command_launcher(), tool->command(), options);
+ WriteCommandRulePattern("command", tool->command_launcher(), tool->command(),
+ options);
WriteRulePattern("description", tool->description(), options);
WriteRulePattern("rspfile", tool->rspfile(), options);
@@ -92,7 +93,7 @@
if (CTool* c_tool = tool->AsC()) {
if (c_tool->depsformat() == CTool::DEPS_GCC) {
// GCC-style deps require a depfile.
- if (!tool->depfile().empty()) {
+ if (!c_tool->depfile().empty()) {
WriteRulePattern("depfile", tool->depfile(), options);
out_ << kIndent << "deps = gcc" << std::endl;
}
diff --git a/src/gn/source_file.cc b/src/gn/source_file.cc
index 0b0e8e5..89c8cf0 100644
--- a/src/gn/source_file.cc
+++ b/src/gn/source_file.cc
@@ -49,6 +49,10 @@
return SourceFile::SOURCE_RS;
if (extension == "go")
return SourceFile::SOURCE_GO;
+ if (extension == "swift")
+ return SourceFile::SOURCE_SWIFT;
+ if (extension == "swiftmodule")
+ return SourceFile::SOURCE_SWIFTMODULE;
return SourceFile::SOURCE_UNKNOWN;
}
@@ -123,8 +127,13 @@
return Get(SourceFile::SOURCE_GO);
}
+bool SourceFileTypeSet::SwiftSourceUsed() const {
+ return Get(SourceFile::SOURCE_SWIFT);
+}
+
bool SourceFileTypeSet::MixedSourceUsed() const {
return (1 << static_cast<int>(CSourceUsed())
<< static_cast<int>(RustSourceUsed())
- << static_cast<int>(GoSourceUsed())) > 2;
+ << static_cast<int>(GoSourceUsed())
+ << static_cast<int>(SwiftSourceUsed())) > 2;
}
diff --git a/src/gn/source_file.h b/src/gn/source_file.h
index 1e156fe..5ad8f62 100644
--- a/src/gn/source_file.h
+++ b/src/gn/source_file.h
@@ -41,6 +41,8 @@
SOURCE_RS,
SOURCE_GO,
+ SOURCE_SWIFT,
+ SOURCE_SWIFTMODULE,
// Must be last.
SOURCE_NUMTYPES,
@@ -158,6 +160,7 @@
bool CSourceUsed() const;
bool RustSourceUsed() const;
bool GoSourceUsed() const;
+ bool SwiftSourceUsed() const;
bool MixedSourceUsed() const;
diff --git a/src/gn/substitution_writer.cc b/src/gn/substitution_writer.cc
index 199faa3..6fe83ce 100644
--- a/src/gn/substitution_writer.cc
+++ b/src/gn/substitution_writer.cc
@@ -576,6 +576,8 @@
} else if (type == &kRustSubstitutionCrateName) {
// Only include the toolchain for non-default toolchains.
return target->rust_values().crate_name();
+ } else if (type == &CSubstitutionSwiftModuleName) {
+ return target->swift_values().module_name();
} else {
NOTREACHED();
return std::string();
diff --git a/src/gn/swift_values.cc b/src/gn/swift_values.cc
new file mode 100644
index 0000000..c15e319
--- /dev/null
+++ b/src/gn/swift_values.cc
@@ -0,0 +1,70 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gn/swift_values.h"
+
+#include "gn/deps_iterator.h"
+#include "gn/err.h"
+#include "gn/settings.h"
+#include "gn/substitution_writer.h"
+#include "gn/target.h"
+
+SwiftValues::SwiftValues() = default;
+
+SwiftValues::~SwiftValues() = default;
+
+bool SwiftValues::OnTargetResolved(const Target* target, Err* err) {
+ if (!FillModuleOuputFile(target, err))
+ return false;
+
+ FillModuleDependencies(target);
+ return true;
+}
+
+void SwiftValues::FillModuleDependencies(const Target* target) {
+ for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
+ if (pair.ptr->toolchain() == target->toolchain() ||
+ pair.ptr->toolchain()->propagates_configs()) {
+ modules_.Append(pair.ptr->swift_values().public_modules().begin(),
+ pair.ptr->swift_values().public_modules().end());
+ }
+ }
+
+ for (const auto& pair : target->public_deps()) {
+ if (pair.ptr->toolchain() == target->toolchain() ||
+ pair.ptr->toolchain()->propagates_configs())
+ public_modules_.Append(pair.ptr->swift_values().public_modules().begin(),
+ pair.ptr->swift_values().public_modules().end());
+ }
+
+ if (builds_module())
+ public_modules_.push_back(target);
+}
+
+bool SwiftValues::FillModuleOuputFile(const Target* target, Err* err) {
+ if (!target->IsBinary() || !target->source_types_used().SwiftSourceUsed())
+ return true;
+
+ const Tool* tool =
+ target->toolchain()->GetToolForSourceType(SourceFile::SOURCE_SWIFT);
+ CHECK(tool->outputs().list().size() >= 1);
+
+ OutputFile module_output_file =
+ SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
+ target, tool, tool->outputs().list()[0]);
+
+ const SourceFile module_output_file_as_source =
+ module_output_file.AsSourceFile(target->settings()->build_settings());
+ if (module_output_file_as_source.type() != SourceFile::SOURCE_SWIFTMODULE) {
+ *err = Err(tool->defined_from(), "Incorrect outputs for tool",
+ "The first output of tool " + std::string(tool->name()) +
+ " must be a .swiftmodule file.");
+ return false;
+ }
+
+ module_output_file_ = std::move(module_output_file);
+ module_output_dir_ = module_output_file_as_source.GetDir();
+
+ return true;
+}
diff --git a/src/gn/swift_values.h b/src/gn/swift_values.h
new file mode 100644
index 0000000..c529738
--- /dev/null
+++ b/src/gn/swift_values.h
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_SWIFT_TARGET_VALUES_H_
+#define TOOLS_GN_SWIFT_TARGET_VALUES_H_
+
+#include <string>
+
+#include "gn/output_file.h"
+#include "gn/source_dir.h"
+#include "gn/source_file.h"
+#include "gn/unique_vector.h"
+
+class Err;
+class Target;
+
+// Holds values specific to target that compile .swift files.
+class SwiftValues {
+ public:
+ SwiftValues();
+ ~SwiftValues();
+
+ SwiftValues(const SwiftValues&) = delete;
+ SwiftValues& operator=(const SwiftValues&) = delete;
+
+ // Called when the target is resolved.
+ bool OnTargetResolved(const Target* target, Err* err);
+
+ // Path of the bridging header.
+ SourceFile& bridge_header() { return bridge_header_; }
+ const SourceFile& bridge_header() const { return bridge_header_; }
+
+ // Name of the module.
+ std::string& module_name() { return module_name_; }
+ const std::string module_name() const { return module_name_; }
+
+ // Returns whether the target generates a .swiftmodule.
+ bool builds_module() const { return module_output_file_ != OutputFile(); }
+
+ // Name of the generated .swiftmodule file. Computed when the target
+ // is resolved.
+ const OutputFile& module_output_file() const { return module_output_file_; }
+
+ // Path of the directory containing the generated .swiftmodule file.
+ // Computed when the target is resolved.
+ const SourceDir& module_output_dir() const { return module_output_dir_; }
+
+ // List of dependent target that generate a .swiftmodule. The current target
+ // is assumed to depend on those modules, and will add them to the module
+ // search path.
+ const UniqueVector<const Target*>& modules() const { return modules_; }
+
+ // List of dependent target that generate a .swiftmodule that are publicly
+ // exported by the current target. This will include the current target if
+ // it generates a .swiftmodule.
+ const UniqueVector<const Target*>& public_modules() const {
+ return public_modules_;
+ }
+
+ private:
+ // Fill informations about .swiftmodule generated by this target.
+ bool FillModuleOuputFile(const Target* target, Err* err);
+
+ // Fill dependencies information on other target generating .swiftmodules.
+ void FillModuleDependencies(const Target* target);
+
+ // Name of the optional bridge header used to import Objective-C classes.
+ // Filled from the target, may be empty even if the target include .swift
+ // source files.
+ SourceFile bridge_header_;
+
+ // Name of the generate module for use by substitution.
+ std::string module_name_;
+
+ // Path to the .swiftmodule generated by this target. Will be empty if the
+ // target does not include .swift sources.
+ OutputFile module_output_file_;
+
+ // Path of the directory containing the .swiftmodule generated by this
+ // target. Will be null if the target does not include .swift sources.
+ SourceDir module_output_dir_;
+
+ // For modules() and public_modules() function. Will be filled when the
+ // target is resolved (can be non-empty even if the target does not build
+ // .swift sources due to transitive dependencies).
+ UniqueVector<const Target*> modules_;
+ UniqueVector<const Target*> public_modules_;
+};
+
+#endif // TOOLS_GN_SWIFT_TARGET_VALUES_H_
diff --git a/src/gn/swift_values_generator.cc b/src/gn/swift_values_generator.cc
new file mode 100644
index 0000000..ba56e28
--- /dev/null
+++ b/src/gn/swift_values_generator.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gn/swift_values_generator.h"
+
+#include "gn/label.h"
+#include "gn/scope.h"
+#include "gn/settings.h"
+#include "gn/swift_values.h"
+#include "gn/swift_variables.h"
+#include "gn/target.h"
+#include "gn/value_extractors.h"
+
+SwiftValuesGenerator::SwiftValuesGenerator(Target* target,
+ Scope* scope,
+ Err* err)
+ : target_(target), scope_(scope), err_(err) {}
+
+SwiftValuesGenerator::~SwiftValuesGenerator() = default;
+
+void SwiftValuesGenerator::Run() {
+ if (!FillBridgeHeader())
+ return;
+
+ if (!FillModuleName())
+ return;
+}
+
+bool SwiftValuesGenerator::FillBridgeHeader() {
+ const Value* value = scope_->GetValue(variables::kSwiftBridgeHeader, true);
+ if (!value)
+ return true;
+
+ if (!value->VerifyTypeIs(Value::STRING, err_))
+ return false;
+
+ SourceFile dest;
+ if (!ExtractRelativeFile(scope_->settings()->build_settings(), *value,
+ scope_->GetSourceDir(), &dest, err_))
+ return false;
+
+ target_->swift_values().bridge_header() = std::move(dest);
+ return true;
+}
+
+bool SwiftValuesGenerator::FillModuleName() {
+ const Value* value = scope_->GetValue(variables::kSwiftModuleName, true);
+ if (!value) {
+ // The target name will be used.
+ target_->swift_values().module_name() = target_->label().name();
+ return true;
+ }
+
+ if (!value->VerifyTypeIs(Value::STRING, err_))
+ return false;
+
+ target_->swift_values().module_name() = std::move(value->string_value());
+ return true;
+}
diff --git a/src/gn/swift_values_generator.h b/src/gn/swift_values_generator.h
new file mode 100644
index 0000000..211c059
--- /dev/null
+++ b/src/gn/swift_values_generator.h
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_SWIFT_TARGET_VALUES_GENERATOR_H_
+#define TOOLS_GN_SWIFT_TARGET_VALUES_GENERATOR_H_
+
+#include <string>
+
+class Err;
+class FunctionCallNode;
+class Scope;
+class Target;
+
+class SwiftValuesGenerator {
+ public:
+ SwiftValuesGenerator(Target* target, Scope* scope, Err* err);
+ ~SwiftValuesGenerator();
+
+ SwiftValuesGenerator(const SwiftValuesGenerator&) = delete;
+ SwiftValuesGenerator& operator=(const SwiftValuesGenerator&) = delete;
+
+ void Run();
+
+ private:
+ bool FillBridgeHeader();
+ bool FillModuleName();
+
+ Target* target_;
+ Scope* scope_;
+ Err* err_;
+};
+
+#endif // TOOLS_GN_SWIFT_TARGET_VALUES_GENERATOR_H_
diff --git a/src/gn/swift_variables.cc b/src/gn/swift_variables.cc
new file mode 100644
index 0000000..cf9d3d4
--- /dev/null
+++ b/src/gn/swift_variables.cc
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gn/swift_variables.h"
+
+namespace variables {
+
+// Swift target vars -----------------------------------------------------
+
+const char kSwiftBridgeHeader[] = "bridge_header";
+const char kSwiftBridgeHeader_HelpShort[] =
+ "bridge_header: [string] Path to C/Objective-C compatibility header.";
+const char kSwiftBridgeHeader_Help[] =
+ R"(bridge_header: [string] Path to C/Objective-C compatibility header.
+
+ Valid for binary targets that contain Swift sources.
+
+ Path to an header that includes C/Objective-C functions and types that
+ needs to be made available to the Swift module.
+)";
+
+const char kSwiftModuleName[] = "module_name";
+const char kSwiftModuleName_HelpShort[] =
+ "module_name: [string] The name for the compiled module.";
+const char kSwiftModuleName_Help[] =
+ R"(module_name: [string] The name for the compiled module.
+
+ Valid for binary targets that contain Swift sources.
+
+ If module_name is not set, then this rule will use the target name.
+)";
+
+void InsertSwiftVariables(VariableInfoMap* info_map) {
+ info_map->insert(std::make_pair(
+ kSwiftBridgeHeader,
+ VariableInfo(kSwiftBridgeHeader_HelpShort, kSwiftBridgeHeader_Help)));
+
+ info_map->insert(std::make_pair(
+ kSwiftModuleName,
+ VariableInfo(kSwiftModuleName_HelpShort, kSwiftModuleName_Help)));
+}
+
+} // namespace variables
diff --git a/src/gn/swift_variables.h b/src/gn/swift_variables.h
new file mode 100644
index 0000000..c430468
--- /dev/null
+++ b/src/gn/swift_variables.h
@@ -0,0 +1,26 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_SWIFT_TARGET_VARIABLES_H_
+#define TOOLS_GN_SWIFT_TARGET_VARIABLES_H_
+
+#include "gn/variables.h"
+
+namespace variables {
+
+// Swift target vars -----------------------------------------------------
+
+extern const char kSwiftBridgeHeader[];
+extern const char kSwiftBridgeHeader_HelpShort[];
+extern const char kSwiftBridgeHeader_Help[];
+
+extern const char kSwiftModuleName[];
+extern const char kSwiftModuleName_HelpShort[];
+extern const char kSwiftModuleName_Help[];
+
+void InsertSwiftVariables(VariableInfoMap* info_map);
+
+} // namespace variables
+
+#endif // TOOLS_GN_SWIFT_TARGET_VARIABLES_H_
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 97e3d37..39bf492 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -388,6 +388,9 @@
if (!FillOutputFiles(err))
return false;
+ if (!swift_values_.OnTargetResolved(this, err))
+ return false;
+
if (!CheckSourceSetLanguages(err))
return false;
if (!CheckVisibility(err))
@@ -598,9 +601,19 @@
if (!tool)
return false; // Tool does not apply for this toolchain.file.
+ // Swift may generate on a module or source level.
+ if (file_type == SourceFile::SOURCE_SWIFT) {
+ if (tool->partial_outputs().list().empty())
+ return false;
+ }
+
+ const SubstitutionList& substitution_list =
+ file_type == SourceFile::SOURCE_SWIFT ? tool->partial_outputs()
+ : tool->outputs();
+
// Figure out what output(s) this compiler produces.
SubstitutionWriter::ApplyListToCompilerAsOutputFile(
- this, source, tool->outputs(), outputs);
+ this, source, substitution_list, outputs);
}
return !outputs->empty();
}
@@ -727,9 +740,12 @@
// If |pair.ptr| is binary target and |pair.ptr| has no public header,
// |this| target does not need to have |pair.ptr|'s hard_deps as its
- // hard_deps to start compiles earlier.
+ // hard_deps to start compiles earlier. Unless the target compiles a
+ // Swift module (since they also generate a header that can be used
+ // by the current target).
if (pair.ptr->IsBinary() && !pair.ptr->all_headers_public() &&
- pair.ptr->public_headers().empty()) {
+ pair.ptr->public_headers().empty() &&
+ !pair.ptr->swift_values().builds_module()) {
continue;
}
diff --git a/src/gn/target.h b/src/gn/target.h
index 6332880..336c20c 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -25,6 +25,7 @@
#include "gn/output_file.h"
#include "gn/rust_values.h"
#include "gn/source_file.h"
+#include "gn/swift_values.h"
#include "gn/toolchain.h"
#include "gn/unique_vector.h"
@@ -210,7 +211,8 @@
bool hard_dep() const {
return output_type_ == ACTION || output_type_ == ACTION_FOREACH ||
output_type_ == COPY_FILES || output_type_ == CREATE_BUNDLE ||
- output_type_ == BUNDLE_DATA || output_type_ == GENERATED_FILE;
+ output_type_ == BUNDLE_DATA || output_type_ == GENERATED_FILE ||
+ (IsBinary() && swift_values().builds_module());
}
// Returns the iterator range which can be used in range-based for loops
@@ -271,6 +273,9 @@
ActionValues& action_values() { return action_values_; }
const ActionValues& action_values() const { return action_values_; }
+ SwiftValues& swift_values() { return swift_values_; }
+ const SwiftValues& swift_values() const { return swift_values_; }
+
RustValues& rust_values() { return rust_values_; }
const RustValues& rust_values() const { return rust_values_; }
@@ -474,6 +479,9 @@
// Used for Rust targets.
RustValues rust_values_;
+ // User for Swift targets.
+ SwiftValues swift_values_;
+
// Toolchain used by this target. Null until target is resolved.
const Toolchain* toolchain_ = nullptr;
diff --git a/src/gn/test_with_scope.cc b/src/gn/test_with_scope.cc
index ae9c939..583eebb 100644
--- a/src/gn/test_with_scope.cc
+++ b/src/gn/test_with_scope.cc
@@ -231,6 +231,17 @@
"{{root_out_dir}}/{{crate_name}}{{output_extension}}"));
toolchain->SetTool(std::move(rustc_tool));
+ // SWIFT
+ std::unique_ptr<Tool> swift_tool = Tool::CreateTool(CTool::kCToolSwift);
+ SetCommandForTool(
+ "swiftc --module-name {{module_name}} {{module_dirs}} {{inputs}}",
+ swift_tool.get());
+ swift_tool->set_outputs(SubstitutionList::MakeForTest(
+ "{{target_out_dir}}/{{module_name}}.swiftmodule"));
+ swift_tool->set_partial_outputs(SubstitutionList::MakeForTest(
+ "{{target_out_dir}}/{{source_name_part}}.o"));
+ toolchain->SetTool(std::move(swift_tool));
+
// CDYLIB
std::unique_ptr<Tool> cdylib_tool = Tool::CreateTool(RustTool::kRsToolCDylib);
SetCommandForTool(
diff --git a/src/gn/tool.cc b/src/gn/tool.cc
index 9fc10ce..5e4186d 100644
--- a/src/gn/tool.cc
+++ b/src/gn/tool.cc
@@ -26,6 +26,7 @@
outputs_.FillRequiredTypes(&substitution_bits_);
rspfile_.FillRequiredTypes(&substitution_bits_);
rspfile_content_.FillRequiredTypes(&substitution_bits_);
+ partial_outputs_.FillRequiredTypes(&substitution_bits_);
}
GeneralTool* Tool::AsGeneral() {
@@ -263,6 +264,8 @@
return std::make_unique<CTool>(CTool::kCToolRc);
else if (name == CTool::kCToolAsm)
return std::make_unique<CTool>(CTool::kCToolAsm);
+ else if (name == CTool::kCToolSwift)
+ return std::make_unique<CTool>(CTool::kCToolSwift);
else if (name == CTool::kCToolAlink)
return std::make_unique<CTool>(CTool::kCToolAlink);
else if (name == CTool::kCToolSolink)
@@ -323,6 +326,8 @@
return CTool::kCToolRc;
case SourceFile::SOURCE_RS:
return RustTool::kRsToolBin;
+ case SourceFile::SOURCE_SWIFT:
+ return CTool::kCToolSwift;
case SourceFile::SOURCE_UNKNOWN:
case SourceFile::SOURCE_H:
case SourceFile::SOURCE_O:
diff --git a/src/gn/tool.h b/src/gn/tool.h
index 7fe6ed5..e64935f 100644
--- a/src/gn/tool.h
+++ b/src/gn/tool.h
@@ -157,6 +157,12 @@
lib_dir_switch_ = std::move(s);
}
+ const std::string& swiftmodule_switch() const { return swiftmodule_switch_; }
+ void set_swiftmodule_switch(std::string s) {
+ DCHECK(!complete_);
+ swiftmodule_switch_ = std::move(s);
+ }
+
const std::string& linker_arg() const { return linker_arg_; }
void set_linker_arg(std::string s) {
DCHECK(!complete_);
@@ -169,6 +175,12 @@
outputs_ = std::move(out);
}
+ const SubstitutionList& partial_outputs() const { return partial_outputs_; }
+ void set_partial_outputs(SubstitutionList partial_out) {
+ DCHECK(!complete_);
+ partial_outputs_ = std::move(partial_out);
+ }
+
const SubstitutionList& runtime_outputs() const { return runtime_outputs_; }
void set_runtime_outputs(SubstitutionList run_out) {
DCHECK(!complete_);
@@ -271,8 +283,10 @@
std::string framework_dir_switch_;
std::string lib_switch_;
std::string lib_dir_switch_;
+ std::string swiftmodule_switch_;
std::string linker_arg_;
SubstitutionList outputs_;
+ SubstitutionList partial_outputs_;
SubstitutionList runtime_outputs_;
std::string output_prefix_;
bool restat_ = false;
diff --git a/src/gn/variables.cc b/src/gn/variables.cc
index b543dd2..d575a14 100644
--- a/src/gn/variables.cc
+++ b/src/gn/variables.cc
@@ -5,6 +5,7 @@
#include "gn/variables.h"
#include "gn/rust_variables.h"
+#include "gn/swift_variables.h"
namespace variables {
@@ -727,7 +728,8 @@
versions of cflags* will be appended on the compiler command line after
"cflags".
- See also "asmflags" for flags for assembly-language files.
+ See also "asmflags" for flags for assembly-language files and "swiftflags"
+ for swift files.
)" COMMON_ORDERING_HELP;
const char* kCflags_Help = kCommonCflagsHelp;
@@ -2017,6 +2019,18 @@
The source are the source files to copy.
)";
+const char kSwiftflags[] = "swiftflags";
+const char kSwiftflags_HelpShort[] =
+ "swiftflags: [string list] Flags passed to the swift compiler.";
+const char* kSwiftflags_Help =
+ R"(swiftflags: Flags passed to the swift compiler.
+
+ A list of strings.
+
+ "swiftflags" are passed to any invocation of a tool that takes an .swift
+ file as input.
+)" COMMON_ORDERING_HELP;
+
const char kXcodeTestApplicationName[] = "xcode_test_application_name";
const char kXcodeTestApplicationName_HelpShort[] =
"xcode_test_application_name: [string] Name for Xcode test target.";
@@ -2307,6 +2321,7 @@
INSERT_VARIABLE(ResponseFileContents)
INSERT_VARIABLE(Script)
INSERT_VARIABLE(Sources)
+ INSERT_VARIABLE(Swiftflags)
INSERT_VARIABLE(XcodeTestApplicationName)
INSERT_VARIABLE(Testonly)
INSERT_VARIABLE(Visibility)
@@ -2317,6 +2332,7 @@
INSERT_VARIABLE(WriteRuntimeDeps)
INSERT_VARIABLE(XcodeExtraAttributes)
InsertRustVariables(&info_map);
+ InsertSwiftVariables(&info_map);
}
return info_map;
}
diff --git a/src/gn/variables.h b/src/gn/variables.h
index acd78af..f5794d1 100644
--- a/src/gn/variables.h
+++ b/src/gn/variables.h
@@ -314,6 +314,10 @@
extern const char kSources_HelpShort[];
extern const char kSources_Help[];
+extern const char kSwiftflags[];
+extern const char kSwiftflags_HelpShort[];
+extern const char* kSwiftflags_Help;
+
extern const char kXcodeTestApplicationName[];
extern const char kXcodeTestApplicationName_HelpShort[];
extern const char kXcodeTestApplicationName_Help[];