// 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
struct DefineWriter {
DefineWriter() {
- options.mode = ESCAPE_SHELL;
+ options.mode = ESCAPE_NINJA_COMMAND;
}
void operator()(const std::string& s, std::ostream& out) const {
};
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) {
#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(
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())
// 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 = ";
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_);
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;
}
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.
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],
}
}
- // 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(
<< 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.
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.
<< 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:
}
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);
}
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.
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));
}
}
}
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_ << " ||";