The go tool, used by many people to build Go programs, handles relative import paths by passing a special option to the compiler. The option is a prefix to use for any relative import. The go tool does this so that programs can be built in a temporary directory and can still find packages imported on a relative path. The gc compiler calls this option -D. This patch adds the same option to gccgo, using the name -fgo-relative-import-path. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.7 branch.
Ian 2012-10-30 Ian Lance Taylor <i...@google.com> * lang.opt (-fgo-relative-import-path): New option. * go-lang.c (go_relative_import_path): New static variable. (go_langhook_init): Pass go_relative_import_path to go_create_gogo. (go_langhook_handle_option): Handle -fgo-relative-import-path. * go-c.h (go_create_gogo): Update declaration. * gccgo.texi (Invoking gccgo): Document -fgo-relative-import-path.
Index: gcc/go/lang.opt =================================================================== --- gcc/go/lang.opt (revision 192992) +++ gcc/go/lang.opt (working copy) @@ -61,6 +61,10 @@ fgo-prefix= Go Joined RejectNegative -fgo-prefix=<string> Set package-specific prefix for exported Go names +fgo-relative-import-path= +Go Joined RejectNegative +-fgo-relative-import-path=<path> Treat a relative import as relative to path + frequire-return-statement Go Var(go_require_return_statement) Init(1) Warning Functions which return values must end with return statements Index: gcc/go/gccgo.texi =================================================================== --- gcc/go/gccgo.texi (revision 192992) +++ gcc/go/gccgo.texi (working copy) @@ -184,6 +184,12 @@ Using either @option{-fgo-pkgpath} or @o the special treatment of the @code{main} package and permits that package to be imported like any other. +@item -fgo-relative-import-path=@var{dir} +@cindex @option{-fgo-relative-import-path} +A relative import is an import that starts with @file{./} or +@file{../}. If this option is used, @command{gccgo} will use +@var{dir} as a prefix for the relative import when searching for it. + @item -frequire-return-statement @itemx -fno-require-return-statement @cindex @option{-frequire-return-statement} Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 192992) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -44,6 +44,7 @@ Gogo::Gogo(Backend* backend, Linemap* li pkgpath_set_(false), pkgpath_from_option_(false), prefix_from_option_(false), + relative_import_path_(), verify_types_(), interface_types_(), specific_type_functions_(), @@ -477,7 +478,8 @@ Gogo::import_package(const std::string& return; } - Import::Stream* stream = Import::open_package(filename, location); + Import::Stream* stream = Import::open_package(filename, location, + this->relative_import_path_); if (stream == NULL) { error_at(location, "import file %qs not found", filename.c_str()); Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 192992) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -206,6 +206,17 @@ class Gogo pkgpath_from_option() const { return this->pkgpath_from_option_; } + // Return the relative import path as set from the command line. + // Returns an empty string if it was not set. + const std::string& + relative_import_path() const + { return this->relative_import_path_; } + + // Set the relative import path from a command line option. + void + set_relative_import_path(const std::string& s) + {this->relative_import_path_ = s; } + // Return the priority to use for the package we are compiling. // This is two more than the largest priority of any package we // import. @@ -732,6 +743,9 @@ class Gogo bool pkgpath_from_option_; // Whether an explicit prefix was set by -fgo-prefix. bool prefix_from_option_; + // The relative import path, from the -fgo-relative-import-path + // option. + std::string relative_import_path_; // A list of types to verify. std::vector<Type*> verify_types_; // A list of interface types defined while parsing. Index: gcc/go/gofrontend/go.cc =================================================================== --- gcc/go/gofrontend/go.cc (revision 192992) +++ gcc/go/gofrontend/go.cc (working copy) @@ -21,7 +21,7 @@ static Gogo* gogo; GO_EXTERN_C void go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath, - const char *prefix) + const char *prefix, const char *relative_import_path) { go_assert(::gogo == NULL); Linemap* linemap = go_get_linemap(); @@ -32,6 +32,9 @@ go_create_gogo(int int_type_size, int po else if (prefix != NULL) ::gogo->set_prefix(prefix); + if (relative_import_path != NULL) + ::gogo->set_relative_import_path(relative_import_path); + // FIXME: This should be in the gcc dependent code. ::gogo->define_builtin_function_trees(); } Index: gcc/go/gofrontend/import.h =================================================================== --- gcc/go/gofrontend/import.h (revision 192992) +++ gcc/go/gofrontend/import.h (working copy) @@ -124,8 +124,10 @@ class Import // 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. LOCATION is the location of the import statement. + // RELATIVE_IMPORT_PATH is used as a prefix for a relative import. static Stream* - open_package(const std::string& filename, Location location); + open_package(const std::string& filename, Location location, + const std::string& relative_import_path); // Constructor. Import(Stream*, Location); Index: gcc/go/gofrontend/import.cc =================================================================== --- gcc/go/gofrontend/import.cc (revision 192992) +++ gcc/go/gofrontend/import.cc (working copy) @@ -41,6 +41,9 @@ go_add_search_path(const char* path) // When FILENAME is not an absolute path and does not start with ./ or // ../, we use the search path provided by -I and -L options. +// When FILENAME does start with ./ or ../, we use +// RELATIVE_IMPORT_PATH as a prefix. + // When FILENAME does not exist, we try modifying FILENAME to find the // file. We use the first of these which exists: // * We append ".gox". @@ -55,19 +58,35 @@ go_add_search_path(const char* path) // later in the search path. Import::Stream* -Import::open_package(const std::string& filename, Location location) +Import::open_package(const std::string& filename, Location location, + const std::string& relative_import_path) { bool is_local; if (IS_ABSOLUTE_PATH(filename)) is_local = true; - else if (filename[0] == '.' && IS_DIR_SEPARATOR(filename[1])) + else if (filename[0] == '.' + && (filename[1] == '\0' || IS_DIR_SEPARATOR(filename[1]))) is_local = true; else if (filename[0] == '.' && filename[1] == '.' - && IS_DIR_SEPARATOR(filename[2])) + && (filename[2] == '\0' || IS_DIR_SEPARATOR(filename[2]))) is_local = true; else is_local = false; + + std::string fn = filename; + if (is_local && !IS_ABSOLUTE_PATH(filename) && !relative_import_path.empty()) + { + if (fn == ".") + { + // A special case. + fn = relative_import_path; + } + else + fn = relative_import_path + '/' + fn; + is_local = false; + } + if (!is_local) { for (std::vector<std::string>::const_iterator p = search_path.begin(); @@ -77,14 +96,14 @@ Import::open_package(const std::string& std::string indir = *p; if (!indir.empty() && indir[indir.size() - 1] != '/') indir += '/'; - indir += filename; + indir += fn; Stream* s = Import::try_package_in_directory(indir, location); if (s != NULL) return s; } } - Stream* s = Import::try_package_in_directory(filename, location); + Stream* s = Import::try_package_in_directory(fn, location); if (s != NULL) return s; Index: gcc/go/go-lang.c =================================================================== --- gcc/go/go-lang.c (revision 192992) +++ gcc/go/go-lang.c (working copy) @@ -85,6 +85,7 @@ struct GTY(()) language_function static const char *go_pkgpath = NULL; static const char *go_prefix = NULL; +static const char *go_relative_import_path = NULL; /* Language hooks. */ @@ -101,7 +102,8 @@ go_langhook_init (void) to, e.g., unsigned_char_type_node) but before calling build_common_builtin_nodes (because it calls, indirectly, go_type_for_size). */ - go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix); + go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix, + go_relative_import_path); build_common_builtin_nodes (); @@ -240,6 +242,10 @@ go_langhook_handle_option ( go_prefix = arg; break; + case OPT_fgo_relative_import_path_: + go_relative_import_path = arg; + break; + default: /* Just return 1 to indicate that the option is valid. */ break; Index: gcc/go/go-c.h =================================================================== --- gcc/go/go-c.h (revision 192992) +++ gcc/go/go-c.h (working copy) @@ -33,7 +33,8 @@ extern int go_enable_optimize (const cha extern void go_add_search_path (const char*); extern void go_create_gogo (int int_type_size, int pointer_size, - const char* pkgpath, const char *prefix); + const char* pkgpath, const char *prefix, + const char *relative_import_path); extern void go_parse_input_files (const char**, unsigned int, bool only_check_syntax,