blob: 96f247f5719a0a580fa874b37ce39bb6351b1e02 [file] [log] [blame]
// Copyright (c) 2016 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 "tools/gn/qt_creator_writer.h"
#include <set>
#include <sstream>
#include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/strings/utf_string_conversions.h"
#include "tools/gn/builder.h"
#include "tools/gn/config_values_extractors.h"
#include "tools/gn/deps_iterator.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/label.h"
#include "tools/gn/loader.h"
namespace {
base::FilePath::CharType kProjectDirName[] =
FILE_PATH_LITERAL("qtcreator_project");
base::FilePath::CharType kProjectName[] = FILE_PATH_LITERAL("all");
base::FilePath::CharType kMainProjectFileSuffix[] =
FILE_PATH_LITERAL(".creator");
base::FilePath::CharType kSourcesFileSuffix[] = FILE_PATH_LITERAL(".files");
base::FilePath::CharType kIncludesFileSuffix[] = FILE_PATH_LITERAL(".includes");
base::FilePath::CharType kDefinesFileSuffix[] = FILE_PATH_LITERAL(".config");
}
// static
bool QtCreatorWriter::RunAndWriteFile(const BuildSettings* build_settings,
const Builder* builder,
Err* err,
const std::string& root_target) {
base::FilePath project_dir =
build_settings->GetFullPath(build_settings->build_dir())
.Append(kProjectDirName);
if (!base::DirectoryExists(project_dir)) {
base::File::Error error;
if (!base::CreateDirectoryAndGetError(project_dir, &error)) {
*err =
Err(Location(), "Could not create the QtCreator project directory '" +
FilePathToUTF8(project_dir) + "': " +
base::File::ErrorToString(error));
return false;
}
}
base::FilePath project_prefix = project_dir.Append(kProjectName);
QtCreatorWriter gen(build_settings, builder, project_prefix, root_target);
gen.Run();
if (gen.err_.has_error()) {
*err = gen.err_;
return false;
}
return true;
}
QtCreatorWriter::QtCreatorWriter(const BuildSettings* build_settings,
const Builder* builder,
const base::FilePath& project_prefix,
const std::string& root_target_name)
: build_settings_(build_settings),
builder_(builder),
project_prefix_(project_prefix),
root_target_name_(root_target_name) {}
QtCreatorWriter::~QtCreatorWriter() {}
void QtCreatorWriter::CollectDeps(const Target* target) {
for (const auto& dep : target->GetDeps(Target::DEPS_ALL)) {
const Target* dep_target = dep.ptr;
if (targets_.count(dep_target))
continue;
targets_.insert(dep_target);
CollectDeps(dep_target);
}
}
bool QtCreatorWriter::DiscoverTargets() {
auto all_targets = builder_->GetAllResolvedTargets();
if (root_target_name_.empty()) {
targets_ = std::set<const Target*>(all_targets.begin(), all_targets.end());
return true;
}
const Target* root_target = nullptr;
for (const Target* target : all_targets) {
if (target->label().name() == root_target_name_) {
root_target = target;
break;
}
}
if (!root_target) {
err_ = Err(Location(), "Target '" + root_target_name_ + "' not found.");
return false;
}
targets_.insert(root_target);
CollectDeps(root_target);
return true;
}
void QtCreatorWriter::AddToSources(const Target::FileList& files) {
for (const SourceFile& file : files) {
const std::string& file_path =
FilePathToUTF8(build_settings_->GetFullPath(file));
sources_.insert(file_path);
}
}
void QtCreatorWriter::HandleTarget(const Target* target) {
SourceFile build_file = Loader::BuildFileForLabel(target->label());
sources_.insert(FilePathToUTF8(build_settings_->GetFullPath(build_file)));
AddToSources(target->settings()->import_manager().GetImportedFiles());
AddToSources(target->sources());
AddToSources(target->public_headers());
AddToSources(target->inputs());
for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
SourceFile precompiled_source = it.cur().precompiled_source();
if (!precompiled_source.is_null()) {
sources_.insert(
FilePathToUTF8(build_settings_->GetFullPath(precompiled_source)));
}
for (const SourceDir& include_dir : it.cur().include_dirs()) {
includes_.insert(
FilePathToUTF8(build_settings_->GetFullPath(include_dir)));
}
for (std::string define : it.cur().defines()) {
size_t equal_pos = define.find('=');
if (equal_pos != std::string::npos)
define[equal_pos] = ' ';
define.insert(0, "#define ");
defines_.insert(define);
}
}
}
void QtCreatorWriter::GenerateFile(const base::FilePath::CharType* suffix,
const std::set<std::string>& items) {
const base::FilePath file_path = project_prefix_.AddExtension(suffix);
std::ostringstream output;
for (const std::string& item : items)
output << item << std::endl;
WriteFileIfChanged(file_path, output.str(), &err_);
}
void QtCreatorWriter::Run() {
if (!DiscoverTargets())
return;
for (const Target* target : targets_) {
if (target->toolchain()->label() !=
builder_->loader()->GetDefaultToolchain())
continue;
HandleTarget(target);
}
std::set<std::string> empty_list;
GenerateFile(kMainProjectFileSuffix, empty_list);
GenerateFile(kSourcesFileSuffix, sources_);
GenerateFile(kIncludesFileSuffix, includes_);
GenerateFile(kDefinesFileSuffix, defines_);
}