blob: 8f95bb8817fc622c0bb76ad0eaa0e2d1f818e47f [file] [log] [blame]
// Copyright (c) 2013 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 <functional>
#include <map>
#include <memory>
#include <set>
#include "base/memory/ref_counted.h"
#include "gn/label.h"
#include "gn/scope.h"
#include "util/msg_loop.h"
class BuildSettings;
class LocationRange;
class Settings;
class SourceFile;
class Toolchain;
// The loader manages execution of the different build files. It receives
// requests (normally from the Builder) when new references are found, and also
// manages loading the build config files.
// This loader class is abstract so it can be mocked out for testing the
// Builder.
class Loader : public base::RefCountedThreadSafe<Loader> {
// Loads the given file in the conext of the given toolchain. The initial
// call to this (the one that actually starts the generation) should have an
// empty toolchain name, which will trigger the load of the default build
// config.
virtual void Load(const SourceFile& file,
const LocationRange& origin,
const Label& toolchain_name) = 0;
// Notification that the given toolchain has loaded. This will unblock files
// waiting on this definition.
virtual void ToolchainLoaded(const Toolchain* toolchain) = 0;
// Returns the label of the default toolchain.
virtual Label GetDefaultToolchain() const = 0;
// Returns information about the toolchain with the given label. Will return
// false if we haven't processed this toolchain yet.
virtual const Settings* GetToolchainSettings(const Label& label) const = 0;
// Returns the build file that the given label references.
virtual SourceFile BuildFileForLabel(const Label& label) const = 0;
// Helper function that extracts the file and toolchain name from the given
// label, and calls Load().
void Load(const Label& label, const LocationRange& origin);
// When processing the default build config, we want to capture the argument
// of set_default_build_config. The implementation of that function uses this
// constant as a property key to get the Label* out of the scope where the
// label should be stored.
static const void* const kDefaultToolchainKey;
friend class base::RefCountedThreadSafe<Loader>;
virtual ~Loader();
class LoaderImpl : public Loader {
// Callback to emulate InputFileManager::AsyncLoadFile.
using AsyncLoadFileCallback =
std::function<bool(const LocationRange&,
const BuildSettings*,
const SourceFile&,
std::function<void(const ParseNode*)>,
explicit LoaderImpl(const BuildSettings* build_settings);
// Loader implementation.
void Load(const SourceFile& file,
const LocationRange& origin,
const Label& toolchain_name) override;
void ToolchainLoaded(const Toolchain* toolchain) override;
Label GetDefaultToolchain() const override;
const Settings* GetToolchainSettings(const Label& label) const override;
SourceFile BuildFileForLabel(const Label& label) const override;
// Sets the task runner corresponding to the main thread. By default this
// class will use the thread active during construction, but there is not
// a task runner active during construction all the time.
void set_task_runner(MsgLoop* task_runner) { task_runner_ = task_runner; }
// The complete callback is called whenever there are no more pending loads.
// Called on the main thread only. This may be called more than once if the
// queue is drained, but then more stuff gets added.
void set_complete_callback(std::function<void()> cb) {
complete_callback_ = std::move(cb);
// This callback is used when the loader finds it wants to load a file.
void set_async_load_file(AsyncLoadFileCallback cb) {
async_load_file_ = std::move(cb);
// Sets the additional extension for build files in this build.
// The resulting file name will be "BUILD.<extension>.gn".
void set_build_file_extension(std::string extension) {
build_file_extension_ = "." + extension;
const Label& default_toolchain_label() const {
return default_toolchain_label_;
struct LoadID;
struct ToolchainRecord;
~LoaderImpl() override;
// Schedules the input file manager to load the given file.
void ScheduleLoadFile(const Settings* settings,
const LocationRange& origin,
const SourceFile& file);
void ScheduleLoadBuildConfig(Settings* settings,
const Scope::KeyValueMap& toolchain_overrides);
// Runs the given file on the background thread. These are called by the
// input file manager.
void BackgroundLoadFile(const Settings* settings,
const SourceFile& file_name,
const LocationRange& origin,
const ParseNode* root);
void BackgroundLoadBuildConfig(Settings* settings,
const Scope::KeyValueMap& toolchain_overrides,
const ParseNode* root);
// Posted to the main thread when any file other than a build config file
// file has completed running.
void DidLoadFile();
// Posted to the main thread when any build config file has completed
// running. The label should be the name of the toolchain.
// If there is no defauled toolchain loaded yet, we'll assume that the first
// call to this indicates to the default toolchain, and this function will
// set the default toolchain name to the given label.
void DidLoadBuildConfig(const Label& label);
// Decrements the pending_loads_ variable and issues the complete callback if
// necessary.
void DecrementPendingLoads();
// Forwards to the appropriate location to load the file.
bool AsyncLoadFile(const LocationRange& origin,
const BuildSettings* build_settings,
const SourceFile& file_name,
std::function<void(const ParseNode*)> callback,
Err* err);
MsgLoop* task_runner_;
int pending_loads_;
std::function<void()> complete_callback_;
// When non-null, use this callback instead of the InputFileManager for
// mocking purposes.
AsyncLoadFileCallback async_load_file_;
using LoadIDSet = std::set<LoadID>;
LoadIDSet invocations_;
const BuildSettings* build_settings_;
Label default_toolchain_label_;
// Records for the build config file loads.
using ToolchainRecordMap = std::map<Label, std::unique_ptr<ToolchainRecord>>;
ToolchainRecordMap toolchain_records_;
std::string build_file_extension_;
#endif // TOOLS_GN_LOADER_H_