aboutsummaryrefslogtreecommitdiff
path: root/c++tools/resolver.cc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-12-14 09:30:00 -0800
committerNathan Sidwell <nathan@acm.org>2020-12-15 07:41:54 -0800
commit35fc243fca06b1ce845a605cd1d6fd199a857e8e (patch)
treeb6f20f124b37e5b2c94c22ddaf660277c6e6d149 /c++tools/resolver.cc
parente831ad4dab9d693885a5654d49e8f219e53eaee1 (diff)
downloadgcc-35fc243fca06b1ce845a605cd1d6fd199a857e8e.zip
gcc-35fc243fca06b1ce845a605cd1d6fd199a857e8e.tar.gz
gcc-35fc243fca06b1ce845a605cd1d6fd199a857e8e.tar.bz2
Add c++tools
Part of our module implementation adds a sample mapper server, the guts of which are used by the default in-process mapping of cc1plus. Rather than add another executable to gcc/cp/, this creates a new c++tools directory where this and any other c++ tools might live. The toplevel changes are a subsequent commit, because ... git. c++tools/ChangeLog: * Makefile.in: New. * config.h.in: New. * configure: New. * configure.ac: New. * resolver.cc: New. * resolver.h: New. * server.cc: New.
Diffstat (limited to 'c++tools/resolver.cc')
-rw-r--r--c++tools/resolver.cc272
1 files changed, 272 insertions, 0 deletions
diff --git a/c++tools/resolver.cc b/c++tools/resolver.cc
new file mode 100644
index 0000000..5028d2a
--- /dev/null
+++ b/c++tools/resolver.cc
@@ -0,0 +1,272 @@
+/* C++ modules. Experimental! -*- c++ -*-
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
+ Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+
+#include "resolver.h"
+// C++
+#include <algorithm>
+// C
+#include <cstring>
+// OS
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+module_resolver::module_resolver (bool map, bool xlate)
+ : default_map (map), default_translate (xlate)
+{
+}
+
+module_resolver::~module_resolver ()
+{
+ if (fd_repo >= 0)
+ close (fd_repo);
+}
+
+bool
+module_resolver::set_repo (std::string &&r, bool force)
+{
+ if (force || repo.empty ())
+ {
+ repo = std::move (r);
+ force = true;
+ }
+ return force;
+}
+
+bool
+module_resolver::add_mapping (std::string &&module, std::string &&file,
+ bool force)
+{
+ auto res = map.emplace (std::move (module), std::move (file));
+ if (res.second)
+ force = true;
+ else if (force)
+ res.first->second = std::move (file);
+
+ return force;
+}
+
+int
+module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
+{
+ struct stat stat;
+ if (fstat (fd, &stat) < 0)
+ return -errno;
+
+ if (!stat.st_size)
+ return 0;
+
+ // Just map the file, we're gonna read all of it, so no need for
+ // line buffering
+ void *buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buffer == MAP_FAILED)
+ return -errno;
+
+ size_t prefix_len = prefix ? strlen (prefix) : 0;
+ unsigned lineno = 0;
+
+ for (char const *begin = reinterpret_cast <char const *> (buffer),
+ *end = begin + stat.st_size, *eol;
+ begin != end; begin = eol + 1)
+ {
+ lineno++;
+ eol = std::find (begin, end, '\n');
+ if (eol == end)
+ // last line has no \n, ignore the line, you lose
+ break;
+
+ auto *pos = begin;
+ bool pfx_search = prefix_len != 0;
+
+ pfx_search:
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ auto *space = pos;
+ while (*space != '\n' && *space != ' ' && *space != '\t')
+ space++;
+
+ if (pos == space)
+ // at end of line, nothing here
+ continue;
+
+ if (pfx_search)
+ {
+ if (size_t (space - pos) == prefix_len
+ && std::equal (pos, space, prefix))
+ pfx_search = false;
+ pos = space;
+ goto pfx_search;
+ }
+
+ std::string module (pos, space);
+ while (*space == ' ' || *space == '\t')
+ space++;
+ std::string file (space, eol);
+
+ if (module[0] == '$')
+ {
+ if (module == "$root")
+ set_repo (std::move (file));
+ else
+ return lineno;
+ }
+ else
+ {
+ if (file.empty ())
+ file = GetCMIName (module);
+ add_mapping (std::move (module), std::move (file), force);
+ }
+ }
+
+ munmap (buffer, stat.st_size);
+
+ return 0;
+}
+
+char const *
+module_resolver::GetCMISuffix ()
+{
+ return "gcm";
+}
+
+module_resolver *
+module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
+ std::string &a, std::string &i)
+{
+ if (!version || version > Cody::Version)
+ s->ErrorResponse ("version mismatch");
+ else if (a != "GCC")
+ // Refuse anything but GCC
+ ErrorResponse (s, std::string ("only GCC supported"));
+ else if (!ident.empty () && ident != i)
+ // Failed ident check
+ ErrorResponse (s, std::string ("bad ident"));
+ else
+ // Success!
+ s->ConnectResponse ("gcc");
+
+ return this;
+}
+
+int
+module_resolver::ModuleRepoRequest (Cody::Server *s)
+{
+ s->PathnameResponse (repo);
+ return 0;
+}
+
+int
+module_resolver::cmi_response (Cody::Server *s, std::string &module)
+{
+ auto iter = map.find (module);
+ if (iter == map.end ())
+ {
+ std::string file;
+ if (default_map)
+ file = std::move (GetCMIName (module));
+ auto res = map.emplace (module, file);
+ iter = res.first;
+ }
+
+ if (iter->second.empty ())
+ s->ErrorResponse ("no such module");
+ else
+ s->PathnameResponse (iter->second);
+
+ return 0;
+}
+
+int
+module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
+ std::string &module)
+{
+ return cmi_response (s, module);
+}
+
+int
+module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
+ std::string &module)
+{
+ return cmi_response (s, module);
+}
+
+int
+module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
+ std::string &include)
+{
+ auto iter = map.find (include);
+ if (iter == map.end () && default_translate)
+ {
+ // Not found, look for it
+ auto file = GetCMIName (include);
+ struct stat statbuf;
+ bool ok = true;
+
+#if HAVE_FSTATAT
+ int fd_dir = AT_FDCWD;
+ if (!repo.empty ())
+ {
+ if (fd_repo == -1)
+ {
+ fd_repo = open (repo.c_str (),
+ O_RDONLY | O_CLOEXEC | O_DIRECTORY);
+ if (fd_repo < 0)
+ fd_repo = -2;
+ }
+ fd_dir = fd_repo;
+ }
+
+ if (!repo.empty () && fd_repo < 0)
+ ok = false;
+ else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
+ || !S_ISREG (statbuf.st_mode))
+ ok = false;
+#else
+ auto append = repo;
+ append.push_back (DIR_SEPARATOR);
+ append.append (file);
+ if (stat (append.c_str (), &statbuf) < 0
+ || !S_ISREG (statbuf.st_mode))
+ ok = false;
+#endif
+ if (!ok)
+ // Mark as not present
+ file.clear ();
+ auto res = map.emplace (include, file);
+ iter = res.first;
+ }
+
+ if (iter == map.end () || iter->second.empty ())
+ s->BoolResponse (false);
+ else
+ s->PathnameResponse (iter->second);
+
+ return 0;
+}
+