Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / gn / ninja_binary_target_writer.cc
index c404006..a5b858e 100644 (file)
@@ -17,7 +17,7 @@ namespace {
 // Returns the proper escape options for writing compiler and linker flags.
 EscapeOptions GetFlagOptions() {
   EscapeOptions opts;
-  opts.mode = ESCAPE_NINJA;
+  opts.mode = ESCAPE_NINJA_COMMAND;
 
   // Some flag strings are actually multiple flags that expect to be just
   // added to the command line. We assume that quoting is done by the
@@ -29,7 +29,7 @@ EscapeOptions GetFlagOptions() {
 
 struct DefineWriter {
   DefineWriter() {
-    options.mode = ESCAPE_SHELL;
+    options.mode = ESCAPE_NINJA_COMMAND;
   }
 
   void operator()(const std::string& s, std::ostream& out) const {
@@ -41,33 +41,20 @@ struct DefineWriter {
 };
 
 struct IncludeWriter {
-  IncludeWriter(PathOutput& path_output,
-                const NinjaHelper& h)
+  IncludeWriter(PathOutput& path_output, const NinjaHelper& h)
       : helper(h),
-        path_output_(path_output),
-        old_inhibit_quoting_(path_output.inhibit_quoting()) {
-    // Inhibit quoting since we'll put quotes around the whole thing ourselves.
-    // Since we're writing in NINJA escaping mode, this won't actually do
-    // anything, but I think we may need to change to shell-and-then-ninja
-    // escaping for this in the future.
-    path_output_.set_inhibit_quoting(true);
+        path_output_(path_output) {
   }
   ~IncludeWriter() {
-    path_output_.set_inhibit_quoting(old_inhibit_quoting_);
   }
 
   void operator()(const SourceDir& d, std::ostream& out) const {
-    out << " \"-I";
-    // It's important not to include the trailing slash on directories or on
-    // Windows it will be a backslash and the compiler might think we're
-    // escaping the quote!
+    out << " -I";
     path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH);
-    out << "\"";
   }
 
   const NinjaHelper& helper;
   PathOutput& path_output_;
-  bool old_inhibit_quoting_;  // So we can put the PathOutput back.
 };
 
 Toolchain::ToolType GetToolTypeForTarget(const Target* target) {
@@ -138,7 +125,16 @@ void NinjaBinaryTargetWriter::WriteCompilerVars() {
 
 #undef WRITE_FLAGS
 
+  // Write some variables about the target for the toolchain definition to use.
+  out_ << "target_name = " << target_->label().name() << std::endl;
+  out_ << "target_out_dir = ";
+  path_output_.WriteDir(out_, helper_.GetTargetOutputDir(target_),
+                        PathOutput::DIR_NO_LAST_SLASH);
   out_ << std::endl;
+  out_ << "root_out_dir = ";
+  path_output_.WriteDir(out_, target_->settings()->toolchain_output_subdir(),
+                        PathOutput::DIR_NO_LAST_SLASH);
+  out_ << std::endl << std::endl;
 }
 
 void NinjaBinaryTargetWriter::WriteSources(
@@ -146,15 +142,21 @@ void NinjaBinaryTargetWriter::WriteSources(
   const Target::FileList& sources = target_->sources();
   object_files->reserve(sources.size());
 
-  std::string implicit_deps = GetSourcesImplicitDeps();
+  std::string implicit_deps =
+      WriteInputDepsStampAndGetDep(std::vector<const Target*>());
 
   for (size_t i = 0; i < sources.size(); i++) {
     const SourceFile& input_file = sources[i];
 
-    SourceFileType input_file_type = GetSourceFileType(input_file,
-                                                       settings_->target_os());
+    SourceFileType input_file_type = GetSourceFileType(input_file);
     if (input_file_type == SOURCE_UNKNOWN)
       continue;  // Skip unknown file types.
+    if (input_file_type == SOURCE_O) {
+      // Object files just get passed to the output and not compiled.
+      object_files->push_back(helper_.GetOutputFileForSource(
+          target_, input_file, input_file_type));
+      continue;
+    }
     std::string command =
         helper_.GetRuleForSourceType(settings_, input_file_type);
     if (command.empty())
@@ -180,7 +182,7 @@ void NinjaBinaryTargetWriter::WriteLinkerStuff(
   // that case?
   OutputFile windows_manifest;
   if (settings_->IsWin()) {
-    windows_manifest.value().assign(helper_.GetTargetOutputDir(target_));
+    windows_manifest = helper_.GetTargetOutputDir(target_);
     windows_manifest.value().append(target_->label().name());
     windows_manifest.value().append(".intermediate.manifest");
     out_ << "manifests = ";
@@ -188,23 +190,9 @@ void NinjaBinaryTargetWriter::WriteLinkerStuff(
     out_ << std::endl;
   }
 
-  WriteLinkerFlags();
-
-  // Append manifest flag on Windows to reference our file.
-  // HACK ERASEME BRETTW FIXME
-  if (settings_->IsWin()) {
-    out_ << " /MANIFEST /ManifestFile:";
-    path_output_.WriteFile(out_, windows_manifest);
-  }
-  out_ << std::endl;
-
-  // Libraries to link.
-  out_ << "libs =";
-  if (settings_->IsMac()) {
-    // TODO(brettw) fix this.
-    out_ << " -framework AppKit -framework ApplicationServices -framework Carbon -framework CoreFoundation -framework Foundation -framework IOKit -framework Security";
-  }
-  out_ << std::endl;
+  const Toolchain::Tool& tool = toolchain_->GetTool(tool_type_);
+  WriteLinkerFlags(tool, windows_manifest);
+  WriteLibs(tool);
 
   // The external output file is the one that other libs depend on.
   OutputFile external_output_file = helper_.GetTargetOutputFile(target_);
@@ -216,7 +204,10 @@ void NinjaBinaryTargetWriter::WriteLinkerStuff(
   OutputFile internal_output_file;
   if (target_->output_type() == Target::SHARED_LIBRARY) {
     if (settings_->IsWin()) {
-      internal_output_file = OutputFile(target_->label().name() + ".dll");
+      internal_output_file.value() =
+          target_->settings()->toolchain_output_subdir().value();
+      internal_output_file.value().append(target_->label().name());
+      internal_output_file.value().append(".dll");
     } else {
       internal_output_file = external_output_file;
     }
@@ -257,7 +248,9 @@ void NinjaBinaryTargetWriter::WriteLinkerStuff(
   out_ << std::endl;
 }
 
-void NinjaBinaryTargetWriter::WriteLinkerFlags() {
+void NinjaBinaryTargetWriter::WriteLinkerFlags(
+    const Toolchain::Tool& tool,
+    const OutputFile& windows_manifest) {
   out_ << "ldflags =";
 
   // First the ldflags from the target and its config.
@@ -265,16 +258,14 @@ void NinjaBinaryTargetWriter::WriteLinkerFlags() {
   RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
                                        flag_options, out_);
 
-  const Toolchain::Tool& tool = toolchain_->GetTool(tool_type_);
-
   // Followed by library search paths that have been recursively pushed
   // through the dependency tree.
   const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs();
   if (!all_lib_dirs.empty()) {
     // Since we're passing these on the command line to the linker and not
     // to Ninja, we need to do shell escaping.
-    PathOutput lib_path_output(path_output_.current_dir(), ESCAPE_NINJA_SHELL,
-                               true);
+    PathOutput lib_path_output(path_output_.current_dir(),
+                               ESCAPE_NINJA_COMMAND);
     for (size_t i = 0; i < all_lib_dirs.size(); i++) {
       out_ << " " << tool.lib_dir_prefix;
       lib_path_output.WriteDir(out_, all_lib_dirs[i],
@@ -282,16 +273,37 @@ void NinjaBinaryTargetWriter::WriteLinkerFlags() {
     }
   }
 
-  // Followed by libraries that have been recursively pushed through the
-  // dependency tree.
+  // Append manifest flag on Windows to reference our file.
+  // HACK ERASEME BRETTW FIXME
+  if (settings_->IsWin()) {
+    out_ << " /MANIFEST /ManifestFile:";
+    path_output_.WriteFile(out_, windows_manifest);
+  }
+  out_ << std::endl;
+}
+
+void NinjaBinaryTargetWriter::WriteLibs(const Toolchain::Tool& tool) {
+  out_ << "libs =";
+
+  // Libraries that have been recursively pushed through the dependency tree.
   EscapeOptions lib_escape_opts;
-  lib_escape_opts.mode = ESCAPE_NINJA_SHELL;
+  lib_escape_opts.mode = ESCAPE_NINJA_COMMAND;
   const OrderedSet<std::string> all_libs = target_->all_libs();
+  const std::string framework_ending(".framework");
   for (size_t i = 0; i < all_libs.size(); i++) {
-    out_ << " " << tool.lib_prefix;
-    EscapeStringToStream(out_, all_libs[i], lib_escape_opts);
-    out_ << "";
+    if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) {
+      // Special-case libraries ending in ".framework" on Mac. Add the
+      // -framework switch and don't add the extension to the output.
+      out_ << " -framework ";
+      EscapeStringToStream(out_,
+          all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()),
+          lib_escape_opts);
+    } else {
+      out_ << " " << tool.lib_prefix;
+      EscapeStringToStream(out_, all_libs[i], lib_escape_opts);
+    }
   }
+  out_ << std::endl;
 }
 
 void NinjaBinaryTargetWriter::WriteLinkCommand(
@@ -308,9 +320,9 @@ void NinjaBinaryTargetWriter::WriteLinkCommand(
        << helper_.GetRulePrefix(target_->settings())
        << Toolchain::ToolTypeToName(tool_type_);
 
-  std::set<OutputFile> extra_object_files;
-  std::vector<const Target*> linkable_deps;
-  std::vector<const Target*> non_linkable_deps;
+  UniqueVector<OutputFile> extra_object_files;
+  UniqueVector<const Target*> linkable_deps;
+  UniqueVector<const Target*> non_linkable_deps;
   GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
 
   // Object files.
@@ -318,10 +330,9 @@ void NinjaBinaryTargetWriter::WriteLinkCommand(
     out_ << " ";
     path_output_.WriteFile(out_, object_files[i]);
   }
-  for (std::set<OutputFile>::iterator i = extra_object_files.begin();
-       i != extra_object_files.end(); ++i) {
+  for (size_t i = 0; i < extra_object_files.size(); i++) {
     out_ << " ";
-    path_output_.WriteFile(out_, *i);
+    path_output_.WriteFile(out_, extra_object_files[i]);
   }
 
   // Libs.
@@ -348,9 +359,9 @@ void NinjaBinaryTargetWriter::WriteSourceSetStamp(
        << helper_.GetRulePrefix(target_->settings())
        << "stamp";
 
-  std::set<OutputFile> extra_object_files;
-  std::vector<const Target*> linkable_deps;
-  std::vector<const Target*> non_linkable_deps;
+  UniqueVector<OutputFile> extra_object_files;
+  UniqueVector<const Target*> linkable_deps;
+  UniqueVector<const Target*> non_linkable_deps;
   GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
 
   // The classifier should never put extra object files in a source set:
@@ -370,24 +381,22 @@ void NinjaBinaryTargetWriter::WriteSourceSetStamp(
 }
 
 void NinjaBinaryTargetWriter::GetDeps(
-    std::set<OutputFile>* extra_object_files,
-    std::vector<const Target*>* linkable_deps,
-    std::vector<const Target*>* non_linkable_deps) const {
+    UniqueVector<OutputFile>* extra_object_files,
+    UniqueVector<const Target*>* linkable_deps,
+    UniqueVector<const Target*>* non_linkable_deps) const {
   const LabelTargetVector& deps = target_->deps();
-  const std::set<const Target*>& inherited = target_->inherited_libraries();
+  const UniqueVector<const Target*>& inherited =
+      target_->inherited_libraries();
 
   // Normal deps.
   for (size_t i = 0; i < deps.size(); i++) {
-    if (inherited.find(deps[i].ptr) != inherited.end())
-      continue;  // Don't add dupes.
     ClassifyDependency(deps[i].ptr, extra_object_files,
                        linkable_deps, non_linkable_deps);
   }
 
   // Inherited libraries.
-  for (std::set<const Target*>::const_iterator i = inherited.begin();
-       i != inherited.end(); ++i) {
-    ClassifyDependency(*i, extra_object_files,
+  for (size_t i = 0; i < inherited.size(); i++) {
+    ClassifyDependency(inherited[i], extra_object_files,
                        linkable_deps, non_linkable_deps);
   }
 
@@ -399,9 +408,9 @@ void NinjaBinaryTargetWriter::GetDeps(
 
 void NinjaBinaryTargetWriter::ClassifyDependency(
     const Target* dep,
-    std::set<OutputFile>* extra_object_files,
-    std::vector<const Target*>* linkable_deps,
-    std::vector<const Target*>* non_linkable_deps) const {
+    UniqueVector<OutputFile>* extra_object_files,
+    UniqueVector<const Target*>* linkable_deps,
+    UniqueVector<const Target*>* non_linkable_deps) const {
   // Only these types of outputs have libraries linked into them. Child deps of
   // static libraries get pushed up the dependency tree until one of these is
   // reached, and source sets don't link at all.
@@ -410,22 +419,26 @@ void NinjaBinaryTargetWriter::ClassifyDependency(
        target_->output_type() == Target::SHARED_LIBRARY);
 
   if (dep->output_type() == Target::SOURCE_SET) {
-    if (target_->output_type() == Target::SOURCE_SET) {
-      // When a source set depends on another source set, add it as a data
-      // dependency so if the user says "ninja second_source_set" it will
-      // also compile the first (what you would expect) even though we'll
-      // never do anything with the first one's files.
-      non_linkable_deps->push_back(dep);
-    } else {
-      // Linking in a source set, copy its object files.
+    // Source sets have their object files linked into final targets (shared
+    // libraries and executables). Intermediate static libraries and other
+    // source sets just forward the dependency, otherwise the files in the
+    // source set can easily get linked more than once which will cause
+    // multiple definition errors.
+    //
+    // In the future, we may need a way to specify a "complete" static library
+    // for cases where you want a static library that includes all source sets
+    // (like if you're shipping that to customers to link against).
+    if (target_->output_type() != Target::SOURCE_SET &&
+        target_->output_type() != Target::STATIC_LIBRARY) {
+      // Linking in a source set to an executable or shared library, copy its
+      // object files.
       for (size_t i = 0; i < dep->sources().size(); i++) {
-        SourceFileType input_file_type = GetSourceFileType(
-            dep->sources()[i], dep->settings()->target_os());
+        SourceFileType input_file_type = GetSourceFileType(dep->sources()[i]);
         if (input_file_type != SOURCE_UNKNOWN &&
             input_file_type != SOURCE_H) {
           // Note we need to specify the target as the source_set target
           // itself, since this is used to prefix the object file name.
-          extra_object_files->insert(helper_.GetOutputFileForSource(
+          extra_object_files->push_back(helper_.GetOutputFileForSource(
               dep, dep->sources()[i], input_file_type));
         }
       }
@@ -438,7 +451,7 @@ void NinjaBinaryTargetWriter::ClassifyDependency(
 }
 
 void NinjaBinaryTargetWriter::WriteImplicitDependencies(
-    const std::vector<const Target*>& non_linkable_deps) {
+    const UniqueVector<const Target*>& non_linkable_deps) {
   const std::vector<SourceFile>& data = target_->data();
   if (!non_linkable_deps.empty() || !data.empty()) {
     out_ << " ||";