mirror of https://github.com/bazelbuild/rules_cc
265 lines
10 KiB
C++
265 lines
10 KiB
C++
// Copyright 2018 The Bazel Authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// Runfiles lookup library for Bazel-built C++ binaries and tests.
|
|
//
|
|
// USAGE:
|
|
// 1. Depend on this runfiles library from your build rule:
|
|
//
|
|
// cc_binary(
|
|
// name = "my_binary",
|
|
// ...
|
|
// deps = ["@rules_cc//cc/runfiles"],
|
|
// )
|
|
//
|
|
// 2. Include the runfiles library.
|
|
//
|
|
// #include "rules_cc/cc/runfiles/runfiles.h"
|
|
//
|
|
// using rules_cc::cc::runfiles::Runfiles;
|
|
//
|
|
// 3. Create a Runfiles object and use rlocation to look up runfile paths:
|
|
//
|
|
// int main(int argc, char** argv) {
|
|
// std::string error;
|
|
// std::unique_ptr<Runfiles> runfiles(
|
|
// Runfiles::Create(argv[0], BAZEL_CURRENT_REPOSITORY, &error));
|
|
//
|
|
// // Important:
|
|
// // If this is a test, use
|
|
// // Runfiles::CreateForTest(BAZEL_CURRENT_REPOSITORY, &error).
|
|
//
|
|
// if (runfiles == nullptr) {
|
|
// ... // error handling
|
|
// }
|
|
// std::string path =
|
|
// runfiles->Rlocation("my_workspace/path/to/my/data.txt");
|
|
// ...
|
|
//
|
|
// The code above creates a Runfiles object and retrieves a runfile path.
|
|
// The BAZEL_CURRENT_REPOSITORY macro is available in every target that
|
|
// depends on the runfiles library.
|
|
//
|
|
// The Runfiles::Create function uses the runfiles manifest and the
|
|
// runfiles directory from the RUNFILES_MANIFEST_FILE and RUNFILES_DIR
|
|
// environment variables. If not present, the function looks for the
|
|
// manifest and directory near argv[0], the path of the main program.
|
|
//
|
|
// To start child processes that also need runfiles, you need to set the right
|
|
// environment variables for them:
|
|
//
|
|
// std::unique_ptr<Runfiles> runfiles(Runfiles::Create(
|
|
// argv[0], BAZEL_CURRENT_REPOSITORY, &error));
|
|
//
|
|
// std::string path = runfiles->Rlocation("path/to/binary"));
|
|
// if (!path.empty()) {
|
|
// ... // create "args" argument vector for execv
|
|
// const auto envvars = runfiles->EnvVars();
|
|
// pid_t child = fork();
|
|
// if (child) {
|
|
// int status;
|
|
// waitpid(child, &status, 0);
|
|
// } else {
|
|
// for (const auto i : envvars) {
|
|
// setenv(i.first.c_str(), i.second.c_str(), 1);
|
|
// }
|
|
// execv(args[0], args);
|
|
// }
|
|
|
|
#ifndef RULES_CC_CC_RUNFILES_RUNFILES_H_
|
|
#define RULES_CC_CC_RUNFILES_RUNFILES_H_ 1
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace rules_cc {
|
|
namespace cc {
|
|
namespace runfiles {
|
|
|
|
class Runfiles {
|
|
public:
|
|
virtual ~Runfiles() {}
|
|
|
|
// Returns a new `Runfiles` instance.
|
|
//
|
|
// Use this from within `cc_test` rules.
|
|
//
|
|
// Returns nullptr on error. If `error` is provided, the method prints an
|
|
// error message into it.
|
|
//
|
|
// This method looks at the RUNFILES_MANIFEST_FILE and TEST_SRCDIR
|
|
// environment variables.
|
|
//
|
|
// If source_repository is not provided, it defaults to the main repository
|
|
// (also known as the workspace).
|
|
static Runfiles* CreateForTest(std::string* error = nullptr);
|
|
static Runfiles* CreateForTest(const std::string& source_repository,
|
|
std::string* error = nullptr);
|
|
|
|
// Returns a new `Runfiles` instance.
|
|
//
|
|
// Use this from `cc_binary` or `cc_library` rules. You may pass an empty
|
|
// `argv0` if `argv[0]` from the `main` method is unknown.
|
|
//
|
|
// Returns nullptr on error. If `error` is provided, the method prints an
|
|
// error message into it.
|
|
//
|
|
// This method looks at the RUNFILES_MANIFEST_FILE and RUNFILES_DIR
|
|
// environment variables. If either is empty, the method looks for the
|
|
// manifest or directory using the other environment variable, or using argv0
|
|
// (unless it's empty).
|
|
//
|
|
// If source_repository is not provided, it defaults to the main repository
|
|
// (also known as the workspace).
|
|
static Runfiles* Create(const std::string& argv0,
|
|
std::string* error = nullptr);
|
|
static Runfiles* Create(const std::string& argv0,
|
|
const std::string& source_repository,
|
|
std::string* error = nullptr);
|
|
|
|
// Returns a new `Runfiles` instance.
|
|
//
|
|
// Use this from any `cc_*` rule if you want to manually specify the paths to
|
|
// the runfiles manifest and/or runfiles directory. You may pass an empty
|
|
// `argv0` if `argv[0]` from the `main` method is unknown.
|
|
//
|
|
// This method is the same as `Create(argv0, error)`, except it uses
|
|
// `runfiles_manifest_file` and `runfiles_dir` as the corresponding
|
|
// environment variable values, instead of looking up the actual environment
|
|
// variables.
|
|
static Runfiles* Create(const std::string& argv0,
|
|
const std::string& runfiles_manifest_file,
|
|
const std::string& runfiles_dir,
|
|
std::string* error = nullptr);
|
|
static Runfiles* Create(const std::string& argv0,
|
|
const std::string& runfiles_manifest_file,
|
|
const std::string& runfiles_dir,
|
|
const std::string& source_repository,
|
|
std::string* error = nullptr);
|
|
|
|
// Returns the runtime path of a runfile.
|
|
//
|
|
// Runfiles are data-dependencies of Bazel-built binaries and tests.
|
|
//
|
|
// The returned path may not exist. The caller should verify the path's
|
|
// existence.
|
|
//
|
|
// The function may return an empty string if it cannot find a runfile.
|
|
//
|
|
// Args:
|
|
// path: runfiles-root-relative path of the runfile; must not be empty and
|
|
// must not contain uplevel references.
|
|
// source_repository: if provided, overrides the source repository set when
|
|
// this Runfiles instance was created.
|
|
// Returns:
|
|
// the path to the runfile, which the caller should check for existence, or
|
|
// an empty string if the method doesn't know about this runfile
|
|
std::string Rlocation(const std::string& path) const;
|
|
std::string Rlocation(const std::string& path,
|
|
const std::string& source_repository) const;
|
|
|
|
// Returns environment variables for subprocesses.
|
|
//
|
|
// The caller should set the returned key-value pairs in the environment of
|
|
// subprocesses, so that those subprocesses can also access runfiles (in case
|
|
// they are also Bazel-built binaries).
|
|
const std::vector<std::pair<std::string, std::string> >& EnvVars() const {
|
|
return envvars_;
|
|
}
|
|
|
|
// Returns a new Runfiles instance that by default uses the provided source
|
|
// repository as a default for all calls to Rlocation.
|
|
//
|
|
// The current instance remains valid.
|
|
std::unique_ptr<Runfiles> WithSourceRepository(
|
|
const std::string& source_repository) const {
|
|
return std::unique_ptr<Runfiles>(new Runfiles(
|
|
runfiles_map_, directory_, repo_mapping_, envvars_, source_repository));
|
|
}
|
|
|
|
private:
|
|
Runfiles(
|
|
std::map<std::string, std::string> runfiles_map, std::string directory,
|
|
std::map<std::pair<std::string, std::string>, std::string> repo_mapping,
|
|
std::vector<std::pair<std::string, std::string> > envvars,
|
|
std::string source_repository)
|
|
: runfiles_map_(std::move(runfiles_map)),
|
|
directory_(std::move(directory)),
|
|
repo_mapping_(std::move(repo_mapping)),
|
|
envvars_(std::move(envvars)),
|
|
source_repository_(std::move(source_repository)) {}
|
|
Runfiles(const Runfiles&) = delete;
|
|
Runfiles(Runfiles&&) = delete;
|
|
Runfiles& operator=(const Runfiles&) = delete;
|
|
Runfiles& operator=(Runfiles&&) = delete;
|
|
|
|
static std::string RlocationUnchecked(
|
|
const std::string& path,
|
|
const std::map<std::string, std::string>& runfiles_map,
|
|
const std::string& directory);
|
|
|
|
const std::map<std::string, std::string> runfiles_map_;
|
|
const std::string directory_;
|
|
const std::map<std::pair<std::string, std::string>, std::string>
|
|
repo_mapping_;
|
|
const std::vector<std::pair<std::string, std::string> > envvars_;
|
|
const std::string source_repository_;
|
|
};
|
|
|
|
// The "testing" namespace contains functions that allow unit testing the code.
|
|
// Do not use these outside of runfiles_test.cc, they are only part of the
|
|
// public API for the benefit of the tests.
|
|
// These functions and their interface may change without notice.
|
|
namespace testing {
|
|
|
|
// For testing only.
|
|
//
|
|
// Computes the path of the runfiles manifest and the runfiles directory.
|
|
//
|
|
// If the method finds both a valid manifest and valid directory according to
|
|
// `is_runfiles_manifest` and `is_runfiles_directory`, then the method sets
|
|
// the corresponding values to `out_manifest` and `out_directory` and returns
|
|
// true.
|
|
//
|
|
// If the method only finds a valid manifest or a valid directory, but not
|
|
// both, then it sets the corresponding output variable (`out_manifest` or
|
|
// `out_directory`) to the value while clearing the other output variable. The
|
|
// method still returns true in this case.
|
|
//
|
|
// If the method cannot find either a valid manifest or valid directory, it
|
|
// clears both output variables and returns false.
|
|
bool TestOnly_PathsFrom(
|
|
const std::string& argv0, std::string runfiles_manifest_file,
|
|
std::string runfiles_dir,
|
|
std::function<bool(const std::string&)> is_runfiles_manifest,
|
|
std::function<bool(const std::string&)> is_runfiles_directory,
|
|
std::string* out_manifest, std::string* out_directory);
|
|
|
|
// For testing only.
|
|
// Returns true if `path` is an absolute Unix or Windows path.
|
|
// For Windows paths, this function does not regard drive-less absolute paths
|
|
// (i.e. absolute-on-current-drive, e.g. "\foo\bar") as absolute and returns
|
|
// false for these.
|
|
bool TestOnly_IsAbsolute(const std::string& path);
|
|
|
|
} // namespace testing
|
|
} // namespace runfiles
|
|
} // namespace cc
|
|
} // namespace rules_cc
|
|
|
|
#endif // RULES_CC_CC_RUNFILES_RUNFILES_H_
|