diff options
author | Ian Lance Taylor <iant@golang.org> | 2023-06-25 20:16:01 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2023-06-26 09:56:29 -0700 |
commit | 3a39a31b8ae9c6465434aefa657f7fcc86f905c0 (patch) | |
tree | 886212591b1c9d127eaaf234a4a2e22452ea384a /gcc | |
parent | 79d8fbbcbf09dfcb6ca18b129fd7841e0eeb0ef5 (diff) | |
download | gcc-3a39a31b8ae9c6465434aefa657f7fcc86f905c0.zip gcc-3a39a31b8ae9c6465434aefa657f7fcc86f905c0.tar.gz gcc-3a39a31b8ae9c6465434aefa657f7fcc86f905c0.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/gccgo.texi | 8 | ||||
-rw-r--r-- | gcc/go/go-c.h | 1 | ||||
-rw-r--r-- | gcc/go/go-lang.cc | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/embed.cc | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 19 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 12 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 124 | ||||
-rw-r--r-- | gcc/go/lang.opt | 4 |
10 files changed, 182 insertions, 7 deletions
diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi index 4ab1a76..90651af 100644 --- a/gcc/go/gccgo.texi +++ b/gcc/go/gccgo.texi @@ -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 @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} @item -g This is the standard @command{gcc} option (@pxref{Debugging Options, , diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h index c605038..6a2b57b 100644 --- a/gcc/go/go-c.h +++ b/gcc/go/go-c.h @@ -41,6 +41,7 @@ struct go_create_gogo_args const char* prefix; const char* relative_import_path; const char* c_header; + const char* importcfg; const char* embedcfg; Backend* backend; Linemap* linemap; diff --git a/gcc/go/go-lang.cc b/gcc/go/go-lang.cc index c6c147b..e85a4bf 100644 --- a/gcc/go/go-lang.cc +++ b/gcc/go/go-lang.cc @@ -90,6 +90,7 @@ static const char *go_prefix = NULL; static const char *go_relative_import_path = NULL; static const char *go_c_header = NULL; static const char *go_embedcfg = NULL; +static const char *go_importcfg = NULL; /* Language hooks. */ @@ -111,6 +112,7 @@ go_langhook_init (void) args.relative_import_path = go_relative_import_path; args.c_header = go_c_header; args.embedcfg = go_embedcfg; + args.importcfg = go_importcfg; args.check_divide_by_zero = go_check_divide_zero; args.check_divide_overflow = go_check_divide_overflow; args.compiling_runtime = go_compiling_runtime; @@ -286,6 +288,10 @@ go_langhook_handle_option ( go_embedcfg = arg; break; + case OPT_fgo_importcfg_: + go_importcfg = arg; + break; + default: /* Just return 1 to indicate that the option is valid. */ break; diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index ff07b1a..c44cdc2 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -68a756b6aadc901534cfddddad2b1e73fae9e34f +92152c88ea8e2dd9e8c67e91bf4ae5e3edf1b506 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/embed.cc b/gcc/go/gofrontend/embed.cc index 0584f70..6dada5e 100644 --- a/gcc/go/gofrontend/embed.cc +++ b/gcc/go/gofrontend/embed.cc @@ -19,8 +19,8 @@ // Read a file into *DATA. Returns false on error. -static bool -read_file(const char* filename, Location loc, std::string* data) +bool +Gogo::read_file(const char* filename, Location loc, std::string* data) { int fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) @@ -346,7 +346,8 @@ Gogo::read_embedcfg(const char *filename) bool 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; if (this->data_.empty()) { @@ -849,7 +850,7 @@ Gogo::initializer_for_embeds(Type* type, } 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); Expression* e = Expression::make_string(data, loc); @@ -909,7 +910,7 @@ Gogo::initializer_for_embeds(Type* type, std::string data; 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); } diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc index 1512770..66d4816 100644 --- a/gcc/go/gofrontend/go.cc +++ b/gcc/go/gofrontend/go.cc @@ -40,6 +40,8 @@ go_create_gogo(const struct go_create_gogo_args* args) ::gogo->set_compiling_runtime(args->compiling_runtime); if (args->c_header != NULL) ::gogo->set_c_header(args->c_header); + if (args->importcfg != NULL) + ::gogo->read_importcfg(args->importcfg); if (args->embedcfg != NULL) ::gogo->read_embedcfg(args->embedcfg); ::gogo->set_debug_escape_level(args->debug_escape_level); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 980db1e..fa3cd6e 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -52,6 +52,10 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) prefix_from_option_(false), relative_import_path_(), c_header_(), + import_map_(), + package_file_(), + embed_patterns_(), + embed_files_(), check_divide_by_zero_(true), check_divide_overflow_(true), compiling_runtime_(false), @@ -517,7 +521,20 @@ Gogo::import_package(const std::string& filename, 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_); if (stream == NULL) { diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index c08a16b..4fd45bf 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -393,6 +393,10 @@ class Gogo set_c_header(const std::string& s) { this->c_header_ = s; } + // Read an importcfg file. + void + read_importcfg(const char* filename); + // Read an embedcfg file. void read_embedcfg(const char* filename); @@ -1126,6 +1130,10 @@ class Gogo static size_t 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: // During parsing, we keep a stack of functions. Each function on // the stack is one that we are currently parsing. For each @@ -1295,6 +1303,10 @@ class Gogo std::string relative_import_path_; // The C header file to write, from the -fgo-c-header option. 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. Embed_patterns embed_patterns_; // Mapping from file to full path from an embedcfg file. diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 6a5491b..21691fa 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -34,6 +34,130 @@ go_add_search_path(const char* 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 // returns a pointer to a Stream object to read the data that it // exports. If the file is not found, it returns NULL. diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt index 4ca989c..0d658fc 100644 --- a/gcc/go/lang.opt +++ b/gcc/go/lang.opt @@ -61,6 +61,10 @@ fgo-embedcfg= Go Joined RejectNegative -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- Go Joined -fgo-optimize-<type> Turn on optimization passes in the frontend. |