Add flag to include additional files in the generated Xcode project
The chromium developer have found it useful to add `*.md` files to
Xcode project so that they can be edited from Xcode. Add an option
to gn Xcode project generator to include them (to remove the need
to use a post-processing of the project in Chromium).
Bug: none
Change-Id: I0ac0eb6529735292b592cff4654259a2b1a61ff9
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/14160
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Sylvain Defresne <sdefresne@chromium.org>
diff --git a/docs/reference.md b/docs/reference.md
index 084398d..ef9a324 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -845,6 +845,17 @@
One useful value is to use Xcode variables such as '${CONFIGURATION}'
or '${EFFECTIVE_PLATFORM}'.
+ --xcode-additional-files-patterns=<pattern_list>
+ If present, must be a list of semicolon-separated file patterns. It
+ will be used to add all files matching the pattern located in the
+ source tree to the project. It can be used to add, e.g. documentation
+ files to the project to allow easily edit them.
+
+ --xcode-additional-files-roots=<path_list>
+ If present, must be a list of semicolon-separated paths. It will be used
+ as roots when looking for additional files to add. If ommitted, defaults
+ to "//".
+
--ninja-executable=<string>
Can be used to specify the ninja executable to use when building.
diff --git a/src/gn/command_gen.cc b/src/gn/command_gen.cc
index fb68cf2..5c6cc14 100644
--- a/src/gn/command_gen.cc
+++ b/src/gn/command_gen.cc
@@ -58,6 +58,9 @@
const char kSwitchXcodeBuildsystemValueNew[] = "new";
const char kSwitchXcodeConfigurations[] = "xcode-configs";
const char kSwitchXcodeConfigurationBuildPath[] = "xcode-config-build-dir";
+const char kSwitchXcodeAdditionalFilesPatterns[] =
+ "xcode-additional-files-patterns";
+const char kSwitchXcodeAdditionalFilesRoots[] = "xcode-additional-files-roots";
const char kSwitchJsonFileName[] = "json-file-name";
const char kSwitchJsonIdeScript[] = "json-ide-script";
const char kSwitchJsonIdeScriptArgs[] = "json-ide-script-args";
@@ -261,6 +264,8 @@
command_line->GetSwitchValueASCII(kSwitchFilters),
command_line->GetSwitchValueASCII(kSwitchXcodeConfigurations),
command_line->GetSwitchValuePath(kSwitchXcodeConfigurationBuildPath),
+ command_line->GetSwitchValueNative(kSwitchXcodeAdditionalFilesPatterns),
+ command_line->GetSwitchValueNative(kSwitchXcodeAdditionalFilesRoots),
XcodeBuildSystem::kLegacy,
};
@@ -537,6 +542,17 @@
One useful value is to use Xcode variables such as '${CONFIGURATION}'
or '${EFFECTIVE_PLATFORM}'.
+ --xcode-additional-files-patterns=<pattern_list>
+ If present, must be a list of semicolon-separated file patterns. It
+ will be used to add all files matching the pattern located in the
+ source tree to the project. It can be used to add, e.g. documentation
+ files to the project to allow easily edit them.
+
+ --xcode-additional-files-roots=<path_list>
+ If present, must be a list of semicolon-separated paths. It will be used
+ as roots when looking for additional files to add. If ommitted, defaults
+ to "//".
+
--ninja-executable=<string>
Can be used to specify the ninja executable to use when building.
diff --git a/src/gn/xcode_object.cc b/src/gn/xcode_object.cc
index ab357bb..4399c55 100644
--- a/src/gn/xcode_object.cc
+++ b/src/gn/xcode_object.cc
@@ -116,6 +116,7 @@
{"js", "sourcecode.javascript"},
{"kext", "wrapper.kext"},
{"m", "sourcecode.c.objc"},
+ {"md", "net.daringfireball.markdown"},
{"mm", "sourcecode.cpp.objcpp"},
{"nib", "wrapper.nib"},
{"o", "compiled.mach-o.objfile"},
diff --git a/src/gn/xcode_writer.cc b/src/gn/xcode_writer.cc
index 0ec1fa8..8216aa4 100644
--- a/src/gn/xcode_writer.cc
+++ b/src/gn/xcode_writer.cc
@@ -15,6 +15,7 @@
#include <utility>
#include "base/environment.h"
+#include "base/files/file_enumerator.h"
#include "base/logging.h"
#include "base/sha1.h"
#include "base/stl_util.h"
@@ -195,6 +196,49 @@
dependent_pbxtarget->AddDependency(std::move(dependency));
}
+// Returns a SourceFile for absolute path `file_path` below `//`.
+SourceFile FilePathToSourceFile(const BuildSettings* build_settings,
+ const base::FilePath& file_path) {
+ const std::string file_path_utf8 = FilePathToUTF8(file_path);
+ return SourceFile("//" + file_path_utf8.substr(
+ build_settings->root_path_utf8().size() + 1));
+}
+
+// Returns the list of patterns to use when looking for additional files
+// from `options`.
+std::vector<base::FilePath::StringType> GetAdditionalFilesPatterns(
+ const XcodeWriter::Options& options) {
+ return base::SplitString(options.additional_files_patterns,
+ FILE_PATH_LITERAL(";"), base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL);
+}
+
+// Returns the list of roots to use when looking for additional files
+// from `options`.
+std::vector<base::FilePath> GetAdditionalFilesRoots(
+ const BuildSettings* build_settings,
+ const XcodeWriter::Options& options) {
+ if (options.additional_files_roots.empty()) {
+ return {build_settings->root_path()};
+ }
+
+ const std::vector<base::FilePath::StringType> roots =
+ base::SplitString(options.additional_files_roots, FILE_PATH_LITERAL(";"),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ std::vector<base::FilePath> root_paths;
+ for (const base::FilePath::StringType& root : roots) {
+ const std::string rebased_root =
+ RebasePath(FilePathToUTF8(root), SourceDir("//"),
+ build_settings->root_path_utf8());
+
+ root_paths.push_back(
+ build_settings->root_path().Append(UTF8ToFilePath(rebased_root)));
+ }
+
+ return root_paths;
+}
+
// Helper class to resolve list of XCTest files per target.
//
// Uses a cache of file found per intermediate targets to reduce the need
@@ -639,14 +683,34 @@
if (!build_settings_->root_path().IsParent(path))
continue;
- const std::string as8bit = path.As8Bit();
- const SourceFile source(
- "//" + as8bit.substr(build_settings_->root_path().value().size() + 1));
-
+ const SourceFile source = FilePathToSourceFile(build_settings_, path);
if (ShouldIncludeFileInProject(source))
sources.insert(source);
}
+ // Add any files from --xcode-additional-files-patterns, using the root
+ // listed in --xcode-additional-files-roots.
+ if (!options_.additional_files_patterns.empty()) {
+ const std::vector<base::FilePath::StringType> patterns =
+ GetAdditionalFilesPatterns(options_);
+ const std::vector<base::FilePath> roots =
+ GetAdditionalFilesRoots(build_settings_, options_);
+
+ for (const base::FilePath& root : roots) {
+ for (const base::FilePath::StringType& pattern : patterns) {
+ base::FileEnumerator it(root, /*recursive*/ true,
+ base::FileEnumerator::FILES, pattern,
+ base::FileEnumerator::FolderSearchPolicy::ALL);
+
+ for (base::FilePath path = it.Next(); !path.empty(); path = it.Next()) {
+ const SourceFile source = FilePathToSourceFile(build_settings_, path);
+ if (ShouldIncludeFileInProject(source))
+ sources.insert(source);
+ }
+ }
+ }
+ }
+
// Sort files to ensure deterministic generation of the project file (and
// nicely sorted file list in Xcode).
std::vector<SourceFile> sorted_sources(sources.begin(), sources.end());
diff --git a/src/gn/xcode_writer.h b/src/gn/xcode_writer.h
index 7edd674..9c960e5 100644
--- a/src/gn/xcode_writer.h
+++ b/src/gn/xcode_writer.h
@@ -56,6 +56,18 @@
// as the project directory.
base::FilePath configuration_build_dir;
+ // If specified, should be a semicolon-separated list of file patterns.
+ // It will be used to add files to the project that are not referenced
+ // from the BUILD.gn files. This is usually used to add documentation
+ // files.
+ base::FilePath::StringType additional_files_patterns;
+
+ // If specified, should be a semicolon-separated list of file roots.
+ // It will be used to add files to the project that are not referenced
+ // from the BUILD.gn files. This is usually used to add documentation
+ // files.
+ base::FilePath::StringType additional_files_roots;
+
// Control which version of the build system should be used for the
// generated Xcode project.
XcodeBuildSystem build_system = XcodeBuildSystem::kLegacy;