compiler: support -fgo-importcfg

* lang.opt (fgo-importcfg): New option.
	* go-c.h (struct go_create_gogo_args): Add importcfg field.
	* go-lang.cc (go_importcfg): New static variable.
	(go_langhook_init): Set args.importcfg.
	(go_langhook_handle_option): Handle -fgo-importcfg.
	* gccgo.texi (Invoking gccgo): Document -fgo-importcfg.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/506095
This commit is contained in:
Ian Lance Taylor 2023-06-25 20:16:01 -07:00
parent 79d8fbbcbf
commit 3a39a31b8a
10 changed files with 182 additions and 7 deletions

View File

@ -271,6 +271,14 @@ pattern to a list of file names, and @code{Files} maps each file name
to a full path to the file. This option is intended for use by the to a full path to the file. This option is intended for use by the
@command{go} command to implement @code{//go:embed}. @command{go} command to implement @code{//go:embed}.
@cindex @option{-fgo-importcfg}
@item -fgo-importcfg=@var{file}
Identify a file that provides mappings for import package paths found
in the Go source files. The file can contain two commands:
@code{importpath} to rename import paths for vendoring and
@code{packagefile} to map from package path to files containing export
data. This option is intended for use by the @command{go} command.
@cindex @option{-g for gccgo} @cindex @option{-g for gccgo}
@item -g @item -g
This is the standard @command{gcc} option (@pxref{Debugging Options, , This is the standard @command{gcc} option (@pxref{Debugging Options, ,

View File

@ -41,6 +41,7 @@ struct go_create_gogo_args
const char* prefix; const char* prefix;
const char* relative_import_path; const char* relative_import_path;
const char* c_header; const char* c_header;
const char* importcfg;
const char* embedcfg; const char* embedcfg;
Backend* backend; Backend* backend;
Linemap* linemap; Linemap* linemap;

View File

@ -90,6 +90,7 @@ static const char *go_prefix = NULL;
static const char *go_relative_import_path = NULL; static const char *go_relative_import_path = NULL;
static const char *go_c_header = NULL; static const char *go_c_header = NULL;
static const char *go_embedcfg = NULL; static const char *go_embedcfg = NULL;
static const char *go_importcfg = NULL;
/* Language hooks. */ /* Language hooks. */
@ -111,6 +112,7 @@ go_langhook_init (void)
args.relative_import_path = go_relative_import_path; args.relative_import_path = go_relative_import_path;
args.c_header = go_c_header; args.c_header = go_c_header;
args.embedcfg = go_embedcfg; args.embedcfg = go_embedcfg;
args.importcfg = go_importcfg;
args.check_divide_by_zero = go_check_divide_zero; args.check_divide_by_zero = go_check_divide_zero;
args.check_divide_overflow = go_check_divide_overflow; args.check_divide_overflow = go_check_divide_overflow;
args.compiling_runtime = go_compiling_runtime; args.compiling_runtime = go_compiling_runtime;
@ -286,6 +288,10 @@ go_langhook_handle_option (
go_embedcfg = arg; go_embedcfg = arg;
break; break;
case OPT_fgo_importcfg_:
go_importcfg = arg;
break;
default: default:
/* Just return 1 to indicate that the option is valid. */ /* Just return 1 to indicate that the option is valid. */
break; break;

View File

@ -1,4 +1,4 @@
68a756b6aadc901534cfddddad2b1e73fae9e34f 92152c88ea8e2dd9e8c67e91bf4ae5e3edf1b506
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.

View File

@ -19,8 +19,8 @@
// Read a file into *DATA. Returns false on error. // Read a file into *DATA. Returns false on error.
static bool bool
read_file(const char* filename, Location loc, std::string* data) Gogo::read_file(const char* filename, Location loc, std::string* data)
{ {
int fd = open(filename, O_RDONLY | O_BINARY); int fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) if (fd < 0)
@ -346,7 +346,8 @@ Gogo::read_embedcfg(const char *filename)
bool bool
Embedcfg_reader::initialize_from_file() Embedcfg_reader::initialize_from_file()
{ {
if (!read_file(this->filename_, Linemap::unknown_location(), &this->data_)) if (!Gogo::read_file(this->filename_, Linemap::unknown_location(),
&this->data_))
return false; return false;
if (this->data_.empty()) if (this->data_.empty())
{ {
@ -849,7 +850,7 @@ Gogo::initializer_for_embeds(Type* type,
} }
std::string data; std::string data;
if (!read_file(this->embed_files_[paths[0]].c_str(), loc, &data)) if (!Gogo::read_file(this->embed_files_[paths[0]].c_str(), loc, &data))
return Expression::make_error(loc); return Expression::make_error(loc);
Expression* e = Expression::make_string(data, loc); Expression* e = Expression::make_string(data, loc);
@ -909,7 +910,7 @@ Gogo::initializer_for_embeds(Type* type,
std::string data; std::string data;
if ((*pp)[pp->size() - 1] != '/') if ((*pp)[pp->size() - 1] != '/')
{ {
if (!read_file(this->embed_files_[*pp].c_str(), loc, &data)) if (!Gogo::read_file(this->embed_files_[*pp].c_str(), loc, &data))
return Expression::make_error(loc); return Expression::make_error(loc);
} }

View File

@ -40,6 +40,8 @@ go_create_gogo(const struct go_create_gogo_args* args)
::gogo->set_compiling_runtime(args->compiling_runtime); ::gogo->set_compiling_runtime(args->compiling_runtime);
if (args->c_header != NULL) if (args->c_header != NULL)
::gogo->set_c_header(args->c_header); ::gogo->set_c_header(args->c_header);
if (args->importcfg != NULL)
::gogo->read_importcfg(args->importcfg);
if (args->embedcfg != NULL) if (args->embedcfg != NULL)
::gogo->read_embedcfg(args->embedcfg); ::gogo->read_embedcfg(args->embedcfg);
::gogo->set_debug_escape_level(args->debug_escape_level); ::gogo->set_debug_escape_level(args->debug_escape_level);

View File

@ -52,6 +52,10 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
prefix_from_option_(false), prefix_from_option_(false),
relative_import_path_(), relative_import_path_(),
c_header_(), c_header_(),
import_map_(),
package_file_(),
embed_patterns_(),
embed_files_(),
check_divide_by_zero_(true), check_divide_by_zero_(true),
check_divide_overflow_(true), check_divide_overflow_(true),
compiling_runtime_(false), compiling_runtime_(false),
@ -517,7 +521,20 @@ Gogo::import_package(const std::string& filename,
return; return;
} }
Import::Stream* stream = Import::open_package(filename, location, // If we are using an importcfg file we have to check two mappings.
// IMPORT_MAP_ is a mapping from package path to real package path,
// for vendoring. PACKAGE_FILE_ is a mapping from package path to
// file name, to find the file in the build cache.
std::string path = filename;
Unordered_map(std::string, std::string)::const_iterator pi;
pi = this->import_map_.find(filename);
if (pi != this->import_map_.end())
path = pi->second;
pi = this->package_file_.find(path);
if (pi != this->package_file_.end())
path = pi->second;
Import::Stream* stream = Import::open_package(path, location,
this->relative_import_path_); this->relative_import_path_);
if (stream == NULL) if (stream == NULL)
{ {

View File

@ -393,6 +393,10 @@ class Gogo
set_c_header(const std::string& s) set_c_header(const std::string& s)
{ this->c_header_ = s; } { this->c_header_ = s; }
// Read an importcfg file.
void
read_importcfg(const char* filename);
// Read an embedcfg file. // Read an embedcfg file.
void void
read_embedcfg(const char* filename); read_embedcfg(const char* filename);
@ -1126,6 +1130,10 @@ class Gogo
static size_t static size_t
special_name_pos(const std::string& name); special_name_pos(const std::string& name);
// Read a file into memory.
static bool
read_file(const char* filename, Location loc, std::string* data);
private: private:
// During parsing, we keep a stack of functions. Each function on // During parsing, we keep a stack of functions. Each function on
// the stack is one that we are currently parsing. For each // the stack is one that we are currently parsing. For each
@ -1295,6 +1303,10 @@ class Gogo
std::string relative_import_path_; std::string relative_import_path_;
// The C header file to write, from the -fgo-c-header option. // The C header file to write, from the -fgo-c-header option.
std::string c_header_; std::string c_header_;
// Mapping from imports in the source file to the real import paths.
Unordered_map(std::string, std::string) import_map_;
// Mapping from import paths to files to read.
Unordered_map(std::string, std::string) package_file_;
// Patterns from an embedcfg file. // Patterns from an embedcfg file.
Embed_patterns embed_patterns_; Embed_patterns embed_patterns_;
// Mapping from file to full path from an embedcfg file. // Mapping from file to full path from an embedcfg file.

View File

@ -34,6 +34,130 @@ go_add_search_path(const char* path)
search_path.push_back(std::string(path)); search_path.push_back(std::string(path));
} }
// Read an importcfg file.
void
Gogo::read_importcfg(const char* filename)
{
std::string data;
if (!Gogo::read_file(filename, Linemap::unknown_location(), &data))
return;
const char* p = data.data();
const char* pend = p + data.length();
int lineno = 0;
const char *pnext = NULL;
for (; p < pend; p = pnext)
{
// Line numbers start at 1.
lineno++;
// Find end of line.
const char* pnl = static_cast<const char*>(memchr(p, '\n', pend - p));
if (pnl != NULL)
pnext = pnl + 1;
else
{
pnl = pend;
pnext = pnl;
}
// Trim leading spaces.
while (p < pnl)
{
unsigned int rune;
int rune_len = Lex::fetch_char(p, &rune);
if (rune_len == 0)
{
go_error_at(Linemap::unknown_location(),
"%s:%d: invalid character in importcfg file",
filename, lineno);
return;
}
if (!Lex::is_unicode_space(rune))
break;
p += rune_len;
}
// Trim trailing spaces.
while (pnl > p)
{
size_t start = pnl - p - 1;
unsigned int rune = (unsigned char)p[start];
int rune_len = 1;
if (rune > 0x7f)
{
for (start--; start > 0; start--)
{
unsigned char c = p[start];
if ((c & 0xc0) != 0x80)
break;
}
rune_len = Lex::fetch_char(p + start, &rune);
if (static_cast<size_t>(rune_len) != (pnl - p) - start)
{
go_error_at(Linemap::unknown_location(),
"%s:%d: invalid character in importcfg file",
filename, lineno);
return;
}
}
if (!Lex::is_unicode_space(rune))
break;
pnl -= rune_len;
}
// Skip empty lines and comment lines.
if (p == pnl || *p == '#')
continue;
size_t verb_len;
const char* psp = static_cast<const char*>(memchr(p, ' ', pnl - p));
if (psp == NULL)
verb_len = pnl - p;
else
verb_len = psp - p;
bool importmap = false;
bool packagefile = false;
if (strncmp(p, "importmap", verb_len) == 0)
importmap = true;
else if (strncmp(p, "packagefile", verb_len) == 0)
packagefile = true;
else
{
go_error_at(Linemap::unknown_location(),
"%s:%d: unknown directive in importcfg file",
filename, lineno);
return;
}
const char* peq;
if (psp == NULL)
peq = NULL;
else
{
psp++;
peq = static_cast<const char*>(memchr(psp, '=', pnl - psp));
}
if (peq == NULL || peq + 1 == pnl)
{
go_error_at(Linemap::unknown_location(),
"%s:%d: invalid syntax in importcfg file",
filename, lineno);
return;
}
std::string first(psp, peq - psp);
std::string second(peq + 1, pnl - (peq + 1));
if (importmap)
this->import_map_[first] = second;
else if (packagefile)
this->package_file_[first] = second;
else
go_unreachable();
}
}
// Find import data. This searches the file system for FILENAME and // Find import data. This searches the file system for FILENAME and
// returns a pointer to a Stream object to read the data that it // returns a pointer to a Stream object to read the data that it
// exports. If the file is not found, it returns NULL. // exports. If the file is not found, it returns NULL.

View File

@ -61,6 +61,10 @@ fgo-embedcfg=
Go Joined RejectNegative Go Joined RejectNegative
-fgo-embedcfg=<file> List embedded files via go:embed. -fgo-embedcfg=<file> List embedded files via go:embed.
fgo-importcfg=
Go Joined RejectNegative
-fgo-importcfg=<file> Provide file that tells where to find imports.
fgo-optimize- fgo-optimize-
Go Joined Go Joined
-fgo-optimize-<type> Turn on optimization passes in the frontend. -fgo-optimize-<type> Turn on optimization passes in the frontend.